题意: 有 n 个金矿,每个金矿开发需要一定的价值,开发之后可以获得一定的价值,而且一些金矿受到另一些金矿的限制,即开采这个金矿之前要开采
限制它的金矿,问最多可以获得多少价值。
分析: 比较明显的最大闭合权图。
建图:
如果某个金矿的开发利润为正值,就在源点和该点之间连一条容量为该利润的边
如果某个金矿的开发利润为负值,就在该点和汇点之间连一条容量为该利润绝对值的边
如果某个金矿收到另一个金矿的限制,就在两个金矿之间连一条容量为INF的边。
累计所有正值利润的和 sum,获得的最大利润为sum - maxflow
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<climits> #define min(a,b)(a)<(b)?(a):(b) const long long INF=1LL<<60; const long long maxn=60000; const long long maxm=2000005; struct node { long long from,to,next,c; }e[maxm]; long long tot; long long head[maxn]; void add(long long s,long long u,long long f1,long long f2) { e[tot].from=s; e[tot].to=u; e[tot].c=f1; e[tot].next=head[s]; head[s]=tot++; e[tot].from=u; e[tot].to=s; e[tot].c=f2; e[tot].next=head[u]; head[u]=tot++; } long long q[maxn]; long long cnt[maxn]; long long d[maxn]; long long low[maxn]; long long cur[maxn]; long long maxflow(long long s,long long t,long long n) { long long *front=q,*rear=q; for(long long i=1;i<=n;i++) { d[i]=n; cnt[i]=0; } cnt[n]=n-1; cnt[0]++; d[t]=0; *rear++=t; while(front<rear) { long long v=*front++; for(long long i=head[v];i!=-1;i=e[i].next) { if(d[e[i].to]==n&&e[i^1].c>0) { d[e[i].to]=d[v]+1; cnt[n]--; cnt[d[e[i].to]]++; *rear++=e[i].to; } } } long long u=s, top=0; long long flow=0; low[0]=INF; for(long long i=1;i<=n;i++) cur[i]=head[i]; while(d[s]<n) { long long &i=cur[u]; for(;i!=-1;i=e[i].next) { if(e[i].c>0&&d[u]==d[e[i].to]+1) { low[top+1]=min(low[top],e[i].c); q[++top]=i; u=e[i].to; break; } } if(i!=-1) { if(u==t) { long long minf=low[top]; for(long long p=1,i;p<=top;++p) { i=q[p]; e[i].c-=minf; e[i^1].c+=minf; } flow+=minf; u=s; low[0]=INF; top=0; } } else { long long old_du=d[u]; cnt[old_du]--; d[u]=n-1; for(long long i=head[u];i!=-1;i=e[i].next) if(e[i].c>0&&d[u]>d[e[i].to]) d[u]=d[e[i].to]; cnt[++d[u]]++; if(d[u]<n) cur[u]=head[u]; if(u!=s) { u=e[q[top]].from; --top; } if(cnt[old_du]==0) break; } } return flow; } int g[105][33]; int main() { long long i,t,n,m,ca=1,tt,j,id; long long sum; scanf("%I64d",&t); while(t--) { scanf("%I64d",&n); id=2; memset(head,-1,sizeof(head)); memset(g,0,sizeof(g)); tt=0; tot=0; sum=0; long long st,en; st=1; en=2; for(i=1;i<=n;i++) { scanf("%I64d",&m); tt+=m; for(j=1;j<=m;j++) { long long cost,va; long long w; scanf("%I64d%I64d%I64d",&cost,&va,&w); if(!g[i][j]) g[i][j]=++id; va-=cost; if(va>0) { add(st,g[i][j],va,0); sum+=va; } else add(g[i][j],en,-va,0); while(w--) { long long a,b; scanf("%I64d%I64d",&a,&b); if(!g[a][b]) g[a][b]=++id; add(g[i][j],g[a][b],INF,0); } } } printf("Case #%I64d: ",ca++); printf("%I64d\n",sum-maxflow(st,en,id)); } return 0; }