[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() {;}
作者:乌鸦坐飞机
出处:http://www.cnblogs.com/whistle13326/
新的风暴已经出现
怎么能够停止不前
穿越时空 竭尽全力
我会来到你身边
微笑面对危险
梦想成真不会遥远
鼓起勇气 坚定向前
奇迹一定会出现