BZOJ1497 [NOI2006] 最大获利

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1497

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

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

Output

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

 

最大权闭合子图,参见2007年国家集训队胡伯涛论文《最小割模型在信息学竞赛中的应用》,参照论文中的方法建图

源点向每一个中转站连流量为费用的边,用户向汇点连流量为收益的边,中转站向对应用户连流量为INF的边

 

关于效率:

参照这道题的实际表现改进了最大流模版的写法,BFS到汇点就跳出能快很多(这个图只有4层,且第三层的点很多),不同的当前弧优化姿势也能影响效率。最快的一份代码跑到了252ms。

 

效率对比:400+ms是另一种当前弧优化的姿势,1000+ms是BFS到汇点不跳出。

 

update: 后来对代码进行了几乎可以忽略的小修改,只快了4ms,要想提高效率估计只有写非递归DFS,或者干脆用ISAP了。但是单纯的提高效率并没有什么意义。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <queue>
 6 #define rep(i,l,r) for(int i=l; i<=r; i++)
 7 #define clr(x,y) memset(x,y,sizeof(x))
 8 #define travel(x) for(int i=last[x]; i!=-1; i=edge[i].pre)
 9 const int INF = 0x7fffffff;
10 const int maxn = 55010;
11 using namespace std;
12 struct Edge{
13     int pre,to,cost;
14 }edge[350000];
15 int n,m,x,y,z,s,t,now,tot=-1,ans=0,total=0,last[maxn],cur[maxn],d[maxn];
16 queue <int> q;
17 inline int read(){
18     int ans = 0, f = 1;
19     char c = getchar();
20     while (!isdigit(c)){
21         if (c == '-') f = -1;
22         c = getchar();
23     }
24     while (isdigit(c)){
25         ans = ans * 10 + c - '0';
26         c = getchar();
27     }
28     return ans * f;
29 }
30 inline void addedge(int x,int y,int z){
31     edge[++tot].pre = last[x];
32     edge[tot].to = y;
33     edge[tot].cost = z;
34     last[x] = tot;
35 }
36 bool bfs(){
37     while (!q.empty()) q.pop();
38     clr(d,-1); d[s] = 0; q.push(s);
39     while (!q.empty()){
40         now = q.front(); q.pop();
41         travel(now){
42             if (d[edge[i].to] == -1 && edge[i].cost > 0){
43                 d[edge[i].to] = d[now] + 1;
44                 q.push(edge[i].to);
45                 if (edge[i].to == t) return 1;
46             }
47         }
48     }
49     return 0;
50 }
51 int dfs(int x,int flow){
52     if (x == t || (!flow)) return flow; int w = 0;
53     for (int i=cur[x]; i!=-1 && w<flow; i=edge[i].pre){
54         if (d[edge[i].to] == d[x] + 1 && edge[i].cost > 0){
55             int delta = dfs(edge[i].to,min(flow-w,edge[i].cost));
56             edge[i].cost -= delta;
57             edge[i^1].cost += delta;
58             w += delta;
59             if (edge[i].cost) cur[x] = i;
60         }
61     }
62     if (w < flow) d[x] = -1;
63     return w;
64 }
65 int main(){
66     n = read(); m = read(); clr(last,-1);
67     s = 0; t = n + m + 1;
68     rep(i,1,n){
69         x = read();
70         addedge(s,i,x); addedge(i,s,0);
71     }
72     rep(i,1,m){
73         x = read(); y = read(); z = read();
74         total += z;
75         addedge(i+n,t,z); addedge(t,i+n,0);
76         addedge(x,i+n,INF); addedge(i+n,x,0);
77         addedge(y,i+n,INF); addedge(i+n,y,0);
78     }
79     while (bfs()){
80         rep(i,0,n+m+1) cur[i] = last[i];
81         int tans = dfs(s,INF);
82         ans += tans;
83     }
84     printf("%d\n",total-ans);
85     return 0;
86 }
View Code

 

posted on 2015-12-09 14:30  ACMICPC  阅读(351)  评论(0编辑  收藏  举报

导航