[NOI2006] 最大获利 (最大权闭合图)

 

                      [NOI2006] 最大获利 

【问题描述】

    新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战。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 公司可以有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才能让公司的净获利最大呢?(净获利 = 获益之和 – 投入成本之和)

【输入文件】

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

【输出文件】

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

【样例输入】

profit.in

5 5 
1 2 3 4 5 
1 2 3 
2 3 4 
1 3 3 
1 4 2 
4 5 3

【样例输出】

profit.out

4

【样例说明】

选择建立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。

 

  1 /*
  2     在cogs上跑了一个rank3 !
  3     跑最大权闭合图 
  4     用 dinic
  5     建图 建立一个源点 连向 n个站点 权值为费用 
  6     m个客户连向汇点 权值为利润 
  7     其他边之间流量为 INF 
  8     跑出最大流 即为不选择建造的站点和不选用户 而损失的利益
  9     总利益减去就好了 
 10 */
 11 #include<queue>
 12 #include<cstdio>
 13 #include<cstring> 
 14 #include<iostream>
 15 #define MAXN 500010
 16 #define INF 0x7fffffff 
 17 
 18 using namespace std;
 19 
 20 struct node {
 21     int to;
 22     int next;
 23     int v;
 24 };
 25 node e[MAXN];
 26 
 27 int head[MAXN<<1],tot=1;
 28 
 29 int n,m,sum,ans,a,b,v,p,src,decc;
 30 
 31 int depth[MAXN<<1],cur[MAXN<<1];
 32 
 33 queue<int> q;
 34 
 35 inline void read(int&x) {
 36     int f=1;x=0;char c=getchar();
 37     while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
 38     while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-48;c=getchar();}
 39     x=x*f;
 40 }
 41 
 42 inline void add(int x,int y,int z) {
 43     e[++tot].to=y;
 44     e[tot].v=z;
 45     e[tot].next=head[x];
 46     head[x]=tot;
 47 }
 48 
 49 inline void add_edge(int x,int y,int z) {
 50     add(x,y,z);
 51     add(y,x,0);
 52 }
 53 
 54 bool bfs() {
 55     for(int i=0;i<=decc;i++) cur[i]=head[i],depth[i]=-1; 
 56     while(!q.empty()) q.pop();
 57     q.push(src);
 58     depth[src]=0;
 59     while(!q.empty()) {
 60         int u=q.front();
 61         q.pop();
 62         for(int i=head[u];i!=-1;i=e[i].next) {
 63             int to=e[i].to;
 64             if(e[i].v&&depth[to]==-1) {
 65                 q.push(to);
 66                 depth[to]=depth[u]+1;
 67                 if(to==decc) return true;
 68             }
 69         }
 70     }
 71     return false;
 72 }
 73 
 74 int dfs(int now,int flow) {
 75     if(now==decc) return flow;
 76     int rest=0,delat;
 77     for(int &i=cur[now];i!=-1;i=e[i].next) {
 78         int to=e[i].to;
 79         if(e[i].v&&depth[to]==depth[now]+1) {
 80             delat=dfs(to,min(e[i].v,flow-rest));
 81             if(delat) {
 82                 e[i].v-=delat;
 83                 e[i^1].v+=delat;
 84                 rest+=delat;
 85                 if(rest==flow) break;
 86             }
 87         }
 88     }
 89     if(flow!=rest) depth[now]=-1;
 90     return rest;
 91 }
 92 
 93 inline void dinic() {
 94     while(bfs()) 
 95       ans+=dfs(src,INF);
 96 }
 97 
 98 int hh() {
 99     freopen("profit.in","r",stdin);
100     freopen("profit.out","w",stdout);
101     read(n);read(m);
102     src=0;decc=n+m+1;
103     memset(head,-1,sizeof head);
104     for(int i=1;i<=n;i++) {
105         read(p);
106         add_edge(src,i,p);
107     }
108     for(int i=1;i<=m;i++) {
109         read(a);read(b);read(v);
110         add_edge(a,n+i,INF);
111         add_edge(b,n+i,INF);
112         add_edge(n+i,decc,v);
113         sum+=v;
114     }
115     dinic();
116     printf("%d\n",sum-ans);
117     return 0;
118 } 
119 
120 int hhh=hh();
121 
122 int main() {;}
题解

 

posted @ 2017-08-09 15:52  拿叉插猹哈  阅读(123)  评论(0编辑  收藏  举报