BZOJ 1497 最大获利(最大权闭合子图)

时间:2021-10-09 11:34:03

http://www.lydsy.com/JudgeOnline/problem.php?id=1497

思路:由题意可以得知,每个顾客都依赖2个中转站,那么让中转站连有向边到汇点,流量为它的建设费用,源点连到每个顾客,流量为赚的钱,然后每个顾客到它依赖的中转站连流量为inf的边

 #include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#define inf 0x7fffffff
int tot,go[],first[],next[],flow[];
int op[],S,T,nodes,dis[],cnt[],n,m;
int read(){
int t=,f=;char ch=getchar();
while (ch<''||ch>''){if (ch=='-') f=-;ch=getchar();}
while (''<=ch&&ch<=''){t=t*+ch-'';ch=getchar();}
return t*f;
}
void insert(int x,int y,int z){
tot++;
go[tot]=y;
next[tot]=first[x];
first[x]=tot;
flow[tot]=z;
}
void add(int x,int y,int z){
insert(x,y,z);op[tot]=tot+;
insert(y,x,);op[tot]=tot-;
}
int dfs(int x,int f){
if (x==T) return f;
int mn=nodes,sum=;
for (int i=first[x];i;i=next[i]){
int pur=go[i];
if (flow[i]&&dis[pur]+==dis[x]){
int save=dfs(pur,std::min(f-sum,flow[i]));
sum+=save;
flow[i]-=save;
flow[op[i]]+=save;
if (f==sum||dis[S]>=nodes) return sum;
}
if (flow[i]) mn=std::min(mn,dis[pur]);
}
if (sum==){
cnt[dis[x]]--;
if (cnt[dis[x]]==){
dis[S]=nodes;
}
else{
dis[x]=mn+;
cnt[dis[x]]++;
}
}
return sum;
}
int main(){
n=read(),m=read();
nodes=n+m+;
T=n+m+;S=;
for (int i=;i<=n;i++){
int x=read();
add(m+i,T,x);
}
int sum=;
for (int i=;i<=m;i++){
int x=read(),y=read(),z=read();
add(S,i,z);
add(i,x+m,inf);
add(i,y+m,inf);
sum+=z;
}
int ans=;
while (dis[S]<nodes) ans+=dfs(S,inf);
printf("%d\n",std::max(sum-ans,));
}