计蒜客 修建机场 解题报告

来源:互联网 发布:淘宝店铺等级快速升级 编辑:程序博客网 时间:2024/04/20 10:13

在蒜头君生活的王国有 nnn 座城市,他们的王国计划在这些城市中修建机场,以方便国民的交通。

iii 座城市修建机场的费用为 pip_ipi。如果某两个城市aaabbb 都修建机场,那么这两个城市的市民就可以很方便地到达对方城市,可以为国家带来的收益为 ccc。求修建机场之后的总收益减去修建机场的总费用的最大值。

输入格式

输入最多包含 202020 组测试数据,以 EOF 结束。对于每组测试数据:

第一行包含两个整数 n,mn,mn,m1≤n≤5000;1≤m≤500001 \leq n \leq 5000 ; 1 \leq m \leq 500001n5000;1m50000),其中mmm 表示可以带来收益的城市对数。

第二行包含 nnn 个整数 pip_ipipi≤1000000p_i \leq 1000000pi1000000)。

接下来 mmm 行每行包含三个整数 a,b,ca,b,ca,b,c1≤a,b≤n;c≤10000001 \leq a , b \leq n ; c \leq 10000001a,bn;c1000000)。

输出格式

对于每组测试数据,输出一个整数。

样例输入

5 55 4 3 2 11 2 42 3 23 4 34 5 43 5 34 15 5 5 51 2 1

样例输出

  4
  0

网络流,最大闭合子图,讲解地址如下: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 100005const int inf = 100000007;#define ll long longstruct 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;    }}