题解:

最小割

答案=总收入-最小割

代码:

#include<bits/stdc++.h> 
const int N=3010,M=4000005; 
using namespace std;  
int fi[N],ne[M],c[M],zz[M],q[N],d[N],a[N],b[N],n,m,num,s,t,ans,sum;  
void jb(int x,int y,int z)  
{  
    zz[num]=y;
    c[num]=z;
    ne[num]=fi[x];
    fi[x]=num++;  
    zz[num]=x;
    c[num]=0;
    ne[num]=fi[y];
    fi[y]=num++;  
}  
int bfs()  
{  
    for (int i=s;i<=t;i++) d[i]=-1;  
    int l=0,r=1;  
    q[1]=s;d[s]=0;  
    while (l<r)  
     {  
        int x=q[++l];  
        for (int p=fi[x];p!=-1;p=ne[p])  
         if (c[p]&&d[zz[p]]==-1)  
          {  
            d[zz[p]]=d[x]+1;  
            q[++r]=zz[p];  
          }  
     }  
    if (d[t]==-1) return 0;
    return 1;  
}  
int find(int x,int low)  
{  
    if (x==t||low==0) return low;  
    int netflow=0;  
    for (int p=fi[x];p!=-1;p=ne[p])  
      if (c[p]&&d[zz[p]]==d[x]+1)  
      {  
        int a=find(zz[p],min(low,c[p]));  
        c[p]-=a;c[p^1]+=a;  
        netflow+=a;low-=a;  
        if (low==0) return netflow;  
      }  
    if (low) d[x]=-1;  
    return netflow;  
}  
int main()  
{  
    scanf("%d",&n);  
    for (int i=1;i<=n;i++)
     {
         scanf("%d",&a[i]);
        sum+=a[i];
     }  
    for (int i=1;i<=n;i++)
     {
         scanf("%d",&b[i]);
        sum+=b[i];
     }  
    memset(fi,-1,sizeof fi);  
    scanf("%d",&m);  
    s=0;t=n+2*m+1;  
    for (int i=1;i<=n;i++)
     {
         jb(s,i,b[i]);
        jb(i,t,a[i]);
     }
    for (int i=1;i<=m;i++)
     {  
        int k,x,c1,c2;  
        scanf("%d%d%d",&k,&c1,&c2);  
        jb(s,n+i*2,c2);  
        jb(n+i*2-1,t,c1);  
        sum+=c1+c2;  
        for (int j=1;j<=k;j++)  
         {  
            scanf("%d",&x);  
            jb(x,n+i*2-1,1e9);  
            jb(n+i*2,x,1e9);  
         }  
     }  
    while (bfs())ans+=find(s,1e9);
    printf("%d\n",sum-ans);  
    return 0;  
}  

 

posted on 2018-02-06 15:16  宣毅鸣  阅读(99)  评论(0编辑  收藏  举报