题解:
最小割
答案=总收入-最小割
代码:
#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; }