题目: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\n",sum-dinic());
}