在蒜头君生活的王国有 nnn 座城市,他们的王国计划在这些城市中修建机场,以方便国民的交通。
第 iii 座城市修建机场的费用为 pip_ipi。如果某两个城市 aaa 和 bbb 都修建机场,那么这两个城市的市民就可以很方便地到达对方城市,可以为国家带来的收益为 ccc。求修建机场之后的总收益减去修建机场的总费用的最大值。
输入格式
输入最多包含 202020 组测试数据,以 EOF 结束。对于每组测试数据:
第一行包含两个整数 n,mn,mn,m(1≤n≤5000;1≤m≤500001 \leq n \leq 5000 ; 1 \leq m \leq 500001≤n≤5000;1≤m≤50000),其中 mmm 表示可以带来收益的城市对数。
第二行包含 nnn 个整数 pip_ipi(pi≤1000000p_i \leq 1000000pi≤1000000)。
接下来 mmm 行每行包含三个整数 a,b,ca,b,ca,b,c(1≤a,b≤n;c≤10000001 \leq a , b \leq n ; c \leq 10000001≤a,b≤n;c≤1000000)。
输出格式
对于每组测试数据,输出一个整数。
样例输入
5 5 5 4 3 2 1 1 2 4 2 3 2 3 4 3 4 5 4 3 5 3 4 1 5 5 5 5 1 2 1
样例输出
40
网络流,最大闭合子图,讲解地址如下:http://www.hihocoder.com/contest/hiho119/problems
建图思路如下:
因为获利=收入-代价,我们需要求的就是使代价最小,我们先假设获得 了全部的收入,这样接下来就容易算代价 假设S割表示被选择了,T割表示没有被选择
做法一:
为每条边建一个新的结点Ci(注意与收入的Ci区分),S向这个结点连容量 为Ci的边表示如果没在S割会造成Ci的代价(也就是相当于收入的逆运 算),此外Ci向这条边所连接的两个点Ai和Bi连一条容量为无穷大的边, 表示如果选了这条边则两侧的点也必须要选。 原来的点向T连一条容量为Pi的边表示如果在S割会造成Pi的代价
代码如下:
#include <bits/stdc++.h>
using namespace std;
#define maxn 100005
const int inf = 100000007;
#define ll long long
struct node{
int to,next;
ll flow;
};
node edge[1000000];
int head[maxn<<1],layer[maxn<<1],cnt,n,m,E;
ll ans;//注意用long long
bool bfs(){
queue<int>q;
memset(layer,-1,sizeof(layer));
layer[0]=0;
q.push(0);
while(!q.empty()){
int now=q.front();
q.pop();
if(now==E)return true;
for(int i=head[now];i!=-1;i=edge[i].next){
if(edge[i].flow && layer[edge[i].to]==-1){
layer[edge[i].to]=layer[now]+1;
q.push(edge[i].to);
}
}
}
return false;
}
ll dfs(int pow,ll flow){
ll sum=0;
if(pow==E)return flow;
for(int i=head[pow];i!=-1;i=edge[i].next){
if(edge[i].flow && layer[edge[i].to]==layer[pow]+1){
ll temp=dfs(edge[i].to,min(edge[i].flow,flow-sum));
edge[i].flow-=temp;
edge[i^1].flow+=temp;
sum+=temp;
if(sum==flow)return sum;
}
}
if(!sum)layer[pow]=-1;
return sum;
}
int dinic(){
while(bfs())ans-=dfs(0,inf);
}
void add(int s,int e,ll flow){
edge[cnt].flow=flow;
edge[cnt].to=e;
edge[cnt].next=head[s];
head[s]=cnt++;
edge[cnt].flow=0;
edge[cnt].to=s;
edge[cnt].next=head[e];
head[e]=cnt++;
}
int main(){
while(cin>>n>>m){
E=n+m+1;
memset(head,-1,sizeof(head));
cnt=0;
for(int i=1;i<=n;i++){
int temp;
scanf("%d",&temp);
add(i,E,temp);
}
ans=0;
for(int i=1;i<=m;i++){
int s,e,v;
scanf("%d%d%d",&s,&e,&v);
ans+=v;
add(0,i+n,v);
add(i+n,s,inf);
add(i+n,e,inf);
}
dinic();
cout<<ans<<endl;
}
}