【BZOJ1497】【NOI2006】—最大获利(网络流/最小割)
考虑到一个问题:
建立中转站是花钱,而满足用户需求是获利
怎么将这两个东西结合起来?
换个角度:
假设我们能满足所有用户的要求
那如果我们选择不满足客户的需求不就是也在花钱了吗
或者说我们把客户的需求看做要花那么多钱
那我们现在就有两个选择了
要么花钱修中转站来满足客户需求
要么花钱来解决客户的需求
我们现在要做的就是找到一种花费最少的方案
来解决所有客户的需求
如果我们把解决需求看做是断开一条边的话
那我们从源点连向所有的中转站,所有的客户连向汇点,有需求的互相连边,花费为边权
我们就是在求这个图的最小割
又由于放弃客户和建中转站显然是矛盾的
连一条为的边就可以了
现在看起来好像就是最大权闭合子图
原谅那时的我太不知道这东西
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=150005;
const int M=400005;
const int inf=20030224;
int n,m,cnt=1,adj[N],tp[N],nxt[M],to[M],cap[M],lev[N],str,des,tot;
inline void addedge(int u,int v,int w){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,cap[cnt]=w;
nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u,cap[cnt]=0;
}
inline bool bfs(){
memset(lev,-1,sizeof(lev));
queue<int> q;
q.push(str),lev[str]=0;
while(!q.empty()){
int u=q.front();q.pop();
for(int e=adj[u];e;e=nxt[e]){
int v=to[e];
if(cap[e]>0&&lev[v]==-1){
lev[v]=lev[u]+1,q.push(v);
if(v==des)return true;
}
}
}
return false;
}
int dinic(int u,int flow){
if(u==des)return flow;
int res=0;
for(int &e=tp[u];e;e=nxt[e]){
int v=to[e];
if(cap[e]>0&&lev[v]==lev[u]+1){
int now=dinic(v,min(flow-res,cap[e]));
cap[e]-=now,cap[e^1]+=now,res+=now;
if(flow==res)return res;
}
}
return res;
}
inline int solve(){
int res=0;
while(bfs()){
memcpy(tp,adj,sizeof(adj));
res+=dinic(str,inf);
}
return res;
}
int main(){
n=read(),m=read();str=n+m+1,des=str+1;
for(int i=1;i<=n;i++){
int p=read();
addedge(str,i,p);
}
for(int i=1;i<=m;i++){
int a=read(),b=read(),c=read();
addedge(a,i+n,inf),addedge(b,i+n,inf);
addedge(i+n,des,c),tot+=c;
}
tot-=solve();
cout<<tot<<'\n';
}