【刷题】BZOJ 4349 最小树形图

Description

小C现在正要攻打科学馆腹地------计算机第三机房。而信息组的同学们已经建好了一座座堡垒,准备迎战。小C作为一种高度智慧的可怕生物,早已对同学们的信息了如指掌。

攻打每一个人的堡垒需要一个代价,而且必须攻打若干次才能把镇守之人灭得灰飞烟灭。

当小C在绞尽脑汁想攻打方案时,突然从XXX的堡垒中滚出来一个纸条:一个惊人的秘密被小C发现了:原来各个堡垒之间会相互提供援助,但是当一个堡垒被攻打时,他对所援助的堡垒的援助就会停止,因为他自己已经自身难保了。也就是说,小C只要攻打某个堡垒一次之后,某些堡垒就只需要花更小的代价攻击了。

现在,要你求消灭全机房要用掉代价最小多少。

Input

第一行一个数N,(N<=50),表示机房修建的堡垒数。

接下来N行,每行两个数,第一个实数Ai表示攻打i号堡垒需要的代价Ai(0<Ai<=1000)。第二个数Bi(0<Bi<100)表示i号堡垒需要被攻打Bi次。

接下来一个数k,表示总共有k组依赖关系。

接下来k行每行三个数x,y,z(x,y,为整数,z为实数),表示攻打过一次x号堡垒之后,攻打y号堡垒就只要花z的代价,保证z比y原来的代价小。

不需要攻打的城堡不允许攻打。

Output

一行,一个实数表示消灭全机房要用的最小代价,保留两位小数。

Sample Input

3
10.00 1
1.80 1
2.50 2
2
1 3 2.00
3 2 1.50

Sample Output

15.50

Solution

最小树形图
首先肯定是到达所有需要到达的点一遍,然后每个点都用最小代价攻打
所以按输入将图建出来,每条边的边权就是攻打代价
然后跑最小树形图,最后贪心增加其它代价

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=50+5,MAXM=MAXN*MAXN;
const db inf=100000000000.00;
int n,m,times[MAXN],vis[MAXN],bel[MAXN],snt,s,pre[MAXN],nd,M[MAXN];
db in[MAXN],G[MAXN][MAXN],ans;
struct node{
    int u,v;
    db k;
};
node side[MAXM];
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline db solve(int rt,int n)
{
    db res=0;
    while(true)
    {
        for(register int i=1;i<=n;++i)in[i]=inf;
        for(register int i=1;i<=snt;++i)
            if(side[i].u!=side[i].v&&in[side[i].v]>side[i].k)in[side[i].v]=side[i].k,pre[side[i].v]=side[i].u;
        for(register int i=1;i<=n;++i)
            if(i!=rt&&in[i]==inf)return -1;
        int cnt=0;
        memset(bel,0,sizeof(bel));
        memset(vis,0,sizeof(vis));
        in[rt]=0;
        for(register int i=1,j;i<=n;++i)
        {
            res+=in[i];j=i;
            while(j!=rt&&vis[j]!=i&&!bel[j])vis[j]=i,j=pre[j];
            if(j!=rt&&!bel[j])
            {
                bel[j]=++cnt;
                for(register int k=pre[j];k!=j;k=pre[k])bel[k]=cnt;
            }
        }
        if(!cnt)break;
        for(register int i=1;i<=n;++i)
            if(!bel[i])bel[i]=++cnt;
        for(register int i=1,u,v;i<=snt;++i)
        {
            u=side[i].u,v=side[i].v;
            side[i].u=bel[u];side[i].v=bel[v];
            if(bel[u]^bel[v])side[i].k-=in[v];
        }
        n=cnt;
        rt=bel[rt];
    }
    return res;
}
int main()
{
    read(n);
    s=++nd;
    for(register int i=1;i<=n;++i)
    {
        in[i]=inf;
        db cost;scanf("%lf",&cost);read(times[i]);
        if(times[i])
        {
            M[i]=++nd;
            side[++snt]=(node){s,M[i],cost};
            chkmin(in[i],cost);
        }
    }
    read(m);
    for(register int i=1;i<=m;++i)
    {
        int x,y;read(x);read(y);
        db cost;scanf("%lf",&cost);
        if(M[x]&&M[y])
        {
            side[++snt]=(node){M[x],M[y],cost};
            chkmin(in[y],cost);
        }
    }
    for(register int i=1;i<=n;++i)
        if(times[i]>1)ans+=(times[i]-1)*in[i];
    printf("%.2f\n",ans+solve(s,nd));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hongyj/p/9285780.html