BZOJ_P1497&Codevs_P1789 最大获利(最大权闭合图最小割最大流)

来源:互联网 发布:seo 知乎 编辑:程序博客网 时间:2024/06/06 10:46

最大获利 2006年NOI全国竞赛
时间限制: 2 s
空间限制: 128000 KB
题目等级 : 大师 Master
题目描述 Description
新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是 挑战。THU 集团旗下的 CS&T 通讯公司在新一代通讯技术血战的前夜,需要做 太多的准备工作,仅就站址选择一项,就需要完成前期市场研究、站址勘测、最 优化等项目。 在前期市场调查和站址勘测之后,公司得到了一共 N 个可以作为通讯信号中 转站的地址,而由于这些地址的地理位置差异,在不同的地方建造通讯中转站需 要投入的成本也是不一样的,所幸在前期调查之后这些都是已知数据:建立第 i 个通讯中转站需要的成本为 Pi(1≤i≤N)。 另外公司调查得出了所有期望中的用户群,一共 M 个。关于第 i 个用户群的 信息概括为 Ai, Bi和 Ci:这些用户会使用中转站 Ai和中转站 Bi进行通讯,公司 可以获益 Ci。(1≤i≤M, 1≤Ai, Bi≤N) THU 集团的 CS&T 公司可以有选择的建立一些中转站(投入成本),为一些 用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才能让 公司的净获利最大呢?(净获利 = 获益之和 – 投入成本之和)

输入描述 Input Description
输入文件中第一行有两个正整数 N 和 M 。 第二行中有 N 个整数描述每一个通讯中转站的建立成本,依次为 P1, P2, …, PN 。 以下 M 行,第(i + 2)行的三个数 Ai, Bi和 Ci描述第 i 个用户群的信息。 所有变量的含义可以参见题目描述。

输出描述 Output Description
你的程序只要向输出文件输出一个整数,表示公司可以得到的最大净获利。

样例输入 Sample Input
5 5
1 2 3 4 5
1 2 3
2 3 4
1 3 3
1 4 2
4 5 3

样例输出 Sample Output
4

数据范围及提示 Data Size & Hint
选择建立 1、2、3 号中转站,则需要投入成本 6,获利为 10,因此得到最大 收益 4。

80%的数据中:N≤200,M≤1 000。

100%的数据中:N≤5 000,M≤50 000,0≤Ci≤100,0≤Pi≤100。

仔细观察问题可以发现,对于获得某一用户群的价值必须建立关于用户群的两个基站,容易想到最大权闭合路
对于每个基站权值为负,而对于每个用户群权值为正,将超级源点与用户群相连,流量为价值,将超级基站与超级汇点相连,流量同样为价值,做超级源点到超级汇点的最大流即可,对于关于最大权闭合图中最优性证明可以去网上参考有关资料;

#include<cstdio>#include<climits>#include<cstring>#include<vector>#include<queue>#include<iostream>using namespace std;#define N 5005#define M 50002#define INF INT_MAX/3*2struct NetWork{    struct Edge{        int fr,to,cap,flow;    };    vector<Edge> edge;vector<int> g[M+N];    bool b[N+M];int d[N+M],p[N+M],cur[N+M];    int n,m,flow,S,T,ans;    void in(int &x){        x=0;char ch=getchar();        while(ch>'9'||ch<'0') ch=getchar();        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();        return;    }    void Add_Edge(int fr,int to,int cap,int flow){        edge.push_back(Edge{fr,to,cap,flow});        edge.push_back(Edge{to,fr,0,0});        int t=edge.size();        g[fr].push_back(t-2);g[to].push_back(t-1);    }    void init(){        in(n),in(m);S=0,T=n+m+1;int x,y,z;        for(int i=1;i<=n;i++){            in(x);Add_Edge(i,T,x,0);        }        for(int i=1;i<=m;i++){            in(x);in(y);in(z);            Add_Edge(S,n+i,z,0);Add_Edge(n+i,x,INF,0);Add_Edge(n+i,y,INF,0);            ans+=z;        }    }    bool bfs(){        memset(b,0,sizeof(b));memset(d,-1,sizeof(d));        queue<int> q;int x;        d[S]=0;b[S]=true;q.push(S);        while(!q.empty()){            x=q.front();q.pop();            for(int i=0;i<g[x].size();i++){                Edge &e=edge[g[x][i]];                if(!b[e.to]&&e.cap>e.flow){                    b[e.to]=true;d[e.to]=d[x]+1;q.push(e.to);                }            }        }        return b[T];    }    void MaxFlow(){        int k,x,mine,minf;        while(bfs()){            memset(cur,0,sizeof(cur));k=0;x=S;            for(;;){                if(x==T){                    mine=-1;minf=INF;                    for(int i=0;i<k;i++){                        Edge &e=edge[p[i]];                        if(e.cap-e.flow<minf){                            minf=e.cap-e.flow;mine=i;                        }                    }                    for(int i=0;i<k;i++){                        edge[p[i]].flow+=minf;                        edge[p[i]^1].flow-=minf;                    }                    flow+=minf;x=edge[p[mine]].fr;k=mine;                }                for(int &i=cur[x];i<g[x].size();i++){                    Edge &e=edge[g[x][i]];                    if(e.cap>e.flow&&d[x]+1==d[e.to]) break;                }                if(cur[x]<g[x].size()){                    p[k++]=g[x][cur[x]];x=edge[g[x][cur[x]]].to;                }                else{                    if(!k) break;                    d[x]=-1;k--;x=edge[p[k]].fr;                }            }        }    }    void solve(){        init();MaxFlow();printf("%d",ans-flow);    }}s;int main(){    s.solve();return 0;}
1 0
原创粉丝点击