题目:BZOJ1497、洛谷P4174。
题目大意:
建中转站需要代价,每个用户需要两个中转站,若都建立则可以得到一定收益。
求最大获益。
解题思路:
最大权闭合子图。
从源向用户连容量为收益的边,从中转站向汇连容量为成本的边。从用户向其需要的中转站连容量inf的边。
然后答案就等于所有用户的收益之和减去最小割。
大概意思就是,割掉收益相当于少了钱,割掉成本相当于花钱,也少了钱,而不可能割掉inf的边。于是就这样。
C++ Code:
#include<cstdio> #include<cctype> #include<cstring> #include<queue> std::queue<int>q; const int inf=0x3f3f3f3f,s=0; struct edge{ int to,nxt,cap; }e[400005]; int cnt=1,n,m,head[150005],t,sum,iter[150005],level[150005]; inline int min(int a,int b){return a<b?a:b;} inline int readint(){ int c=getchar(),d=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } inline void addedge(int f,int t,int c){ e[++cnt]=(edge){t,head[f],c}; head[f]=cnt; e[++cnt]=(edge){f,head[t],0}; head[t]=cnt; } void bfs(){ level[s]=1; for(q.push(s);!q.empty();){ int u=q.front(); q.pop(); for(int i=head[u];~i;i=e[i].nxt) if(e[i].cap&&level[e[i].to]==-1){ level[e[i].to]=level[u]+1; q.push(e[i].to); } } } int dfs(int u,int f){ if(!f||u==t)return f; for(int& i=iter[u];~i;i=e[i].nxt) if(e[i].cap&&level[e[i].to]>level[u]){ int d=dfs(e[i].to,min(f,e[i].cap)); if(d){ e[i].cap-=d; e[i^1].cap+=d; return d; }else level[e[i].to]=-1; } return 0; } int dinic(){ for(int flow=0,f;;){ memset(level,-1,sizeof level); bfs(); if(level[t]<0)return flow; memcpy(iter,head,sizeof iter); while(f=dfs(s,inf))flow+=f; } } int main(){ n=readint(),m=readint(); t=n+m+1; memset(head,-1,sizeof head); for(int i=1;i<=n;++i){ int p=readint(); addedge(i+m,t,p); } for(int i=1;i<=m;++i){ int a=readint(),b=readint(),c=readint(); sum+=c; addedge(s,i,c); addedge(i,a+m,inf); addedge(i,b+m,inf); } return!printf("%d ",sum-dinic()); }