原文链接http://www.cnblogs.com/zhouzhendong/p/8371052.html
题目传送门 - BZOJ1497
题意概括
有n个站要被建立。
建立第i个站的花费为pi。
特别的,当第Ai和Bi都被建立时可以得到收益Ci.
问最大收益为多少。
题解
做法特别巧妙。
我们假装所有的Ci都可以被取到。
然后我们考虑至少要失去多少。
我们对于所有站i,建立S->i的边,边权为Pi.
对于所有的i,建立Ai->i+n,Bi->i+n边权为INF,以及i+n->T,边权为Ci。
然后要失去的价值要尽量小,于是我们只需要求得最小割即可。
由于最小割=最大流,所以SAP跑一跑即可。
代码
#include <cstring> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> using namespace std; const int N=55005,M=N*3*2,INF=1e9; struct edge{ int x,y,cap,flow,nxt; }; struct gragh{ int cnt,fst[N],dist[N],n,S,T,num[N],cur[N],p[N]; int q[N],head,tail; edge e[M]; void set(int _S,int _T,int _n){ S=_S,T=_T,n=_n,cnt=1; memset(fst,0,sizeof fst); } void add(int a,int b,int c){ cnt++; e[cnt].x=a,e[cnt].y=b,e[cnt].cap=c,e[cnt].flow=0; e[cnt].nxt=fst[a],fst[a]=cnt; cnt++; e[cnt].x=b,e[cnt].y=a,e[cnt].cap=0,e[cnt].flow=0; e[cnt].nxt=fst[b],fst[b]=cnt; } void bfs(){ memset(dist,-1,sizeof dist); head=tail=dist[T]=0; q[++tail]=T; while (head<tail) for (int x=q[++head],y,i=fst[x];i;i=e[i].nxt) if ((i&1)&&dist[y=e[i].y]==-1) dist[q[++tail]=y]=dist[x]+1; for (int i=1;i<=n;i++) if (dist[i]==-1) dist[i]=n; } void init(){ bfs(); memset(num,0,sizeof num); for (int i=1;i<=n;i++) num[dist[i]]++,cur[i]=fst[i]; } int Augment(int &x){ int ex_flow=INF; for (int i=T;i!=S;i=e[p[i]].x) if (e[p[i]].cap-e[p[i]].flow<=ex_flow) ex_flow=e[p[i]].cap-e[p[i]].flow,x=e[p[i]].x; for (int i=T;i!=S;i=e[p[i]].x) e[p[i]].flow+=ex_flow,e[p[i]^1].flow-=ex_flow; return ex_flow; } int ISAP(){ int x=S,y,MaxFlow=0; init(); while (dist[S]<n){ if (x==T){ MaxFlow+=Augment(x); continue; } bool found=0; for (int i=cur[x];i;i=e[i].nxt) if (dist[y=e[i].y]+1==dist[x]&&e[i].cap>e[i].flow){ cur[x]=p[y]=i,x=y,found=1; break; } if (!found){ int d=n+1; for (int i=fst[x];i;i=e[i].nxt) if (e[i].cap>e[i].flow) d=min(d,dist[e[i].y]+1); if (!--num[dist[x]]) return MaxFlow; num[dist[x]=d]++,cur[x]=fst[x],x=x==S?x:e[p[x]].x; } } return MaxFlow; } }g; int n,m,S,T,p[5005],A[50005],B[50005],C[50005]; int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&p[i]); int total=0; for (int i=1;i<=m;i++) scanf("%d%d%d",&A[i],&B[i],&C[i]),total+=C[i]; S=n+m+1,T=n+m+2; g.set(S,T,n+m+2); for (int i=1;i<=n;i++) g.add(S,i,p[i]); for (int i=1;i<=m;i++){ g.add(A[i],i+n,INF); g.add(B[i],i+n,INF); g.add(i+n,T,C[i]); } printf("%d",total-g.ISAP()); return 0; }