hdu 3879 Base Station (最大权 闭合图)
http://acm.hdu.edu.cn/showproblem.php?pid=3879
好纠结的一道题啊 ,竟然 卡网络流的算法 。。。。。。用 dinic tle 。。。。改为 isap 过了。。。。。。。
题意:
有n<= 5000个点可以用来建Station,题目给出了m个xi yi ci表示建立xi和yi个站点公司将获利ci,修建每个站点还需要成本, 让你求如何修建站点能使公司的收益最大?
题解:
找出依赖关系 要获得利益 ci 则 要 有建立 站 a 和 站 b 所以 添加一个 点 c 权值 为正 ,要修的 站 权值 为 负 连接 c->a .c->b ;
然后 求 最大权闭合图 即可!!
1 #include<cstdio>
2 #include<cstring>
3 #include<cmath>
4 #include<iostream>
5 #include<algorithm>
6 #include<set>
7 #include<map>
8 #include<queue>
9 #include<vector>
10 #include<string>
11 #define inf 0x7fffffff
12 #define maxn 60000
13 #define CL(a,b) memset(a,b,sizeof(a))
14
15 using namespace std;
16 struct node
17 {
18 int to;
19 int cap;
20 int next;
21 }p[maxn*10] ;
22 int dis[maxn],gap[maxn] ,cnt,next[maxn],s,e;// dis[i]为 到达 原点的层数
23 int n , m,NN ;//NN 为 加完点 之后的 总结点数
24 void add(int from,int to,int cap)//加 的 是 有向边
25 {
26 p[cnt].to = to;
27 p[cnt].cap = cap ;
28 p[cnt].next = next[from];
29 next[from] = cnt++;
30
31 p[cnt].to = from;
32 p[cnt].cap = 0;
33 p[cnt].next = next[to];
34 next[to] = cnt++ ;
35 }
36 int dfs(int pos,int cost)
37 {
38
39 if(pos == e)
40 return cost ;
41
42 int i,j ,mdis = NN ,f = cost ;
43
44 for(i = next[pos];i != - 1; i = p[i].next)
45 {
46 int to = p[i].to ;
47 int cap = p[i].cap ;
48 if(cap > 0 )
49 {
50 if(dis[to] + 1 == dis[pos])
51 {
52
53
54 int d = min(f,cap) ;// 注意 这 为 剩余 流量 和 cap 的 最小值
55
56 d = dfs(to,d) ;
57 p[i].cap -=d;
58 p[i^1].cap +=d;
59 f -= d;
60
61 if(dis[s] >= NN) return cost - f;// 如果没有 了 增广路经 结束算法
62 if(f == 0) break ;
63 }
64 if( dis[to] < mdis ) mdis = dis[to] ;// 记录可扩展的最小的狐
65
66 }
67
68 }
69 if(f == cost)// 没有 可以 扩展的点
70 {
71 --gap[dis[pos]];
72 if(gap[dis[pos]] == 0)dis[s] = NN;// 注意这 ,若 距离 为 dis[pos] 这一层都没有 扩展点了(断层) dis[s] = n
73
74 dis[pos] = mdis + 1;//维护距离标号的方法是这样的:当找增广路过程中发现某点出发没有允许弧时,将这个点的距离标号设为由它出发的所有弧的终点的距离标号的最 小值加一
75
76 ++gap[dis[pos]] ;
77 }
78 return cost - f ;
79 }
80 int isap( int b,int t)
81 {
82
83 int ret = 0;
84 s = b;
85 e = t;
86 CL(gap,0);
87 CL(dis,0) ;
88 gap[s] = NN ;//NN 为 加完点 之后的 总结点数
89 while(dis[s] < NN)
90 {
91 ret+=dfs(s,inf) ;
92 }
93 return ret ;
94
95 }
96 int a[maxn] ;
97 int main()
98 {
99 //read() ;
100 int i, x,y;
101 int d ;
102 while(scanf("%d%d",&n,&m)!=EOF)
103 {
104 int sum = 0 ;
105
106 CL(next, -1);
107
108
109 cnt = 0 ;
110 int b = 0 ;
111 int t = n + m + 1 ;
112 NN = n + m + 2;
113 for(i = 1; i <= n;i++)
114 {
115 scanf("%d",&a[i]) ;
116 add(i,t,a[i]) ;
117 }
118
119
120 for(i = 1 ; i <= m;i++)
121 {
122 scanf("%d%d%d",&x,&y,&d);
123
124 add(b,n+i,d) ;
125
126 sum += d ;
127
128 add(n + i,x,inf) ;
129
130
131 add(n + i ,y,inf) ;
132
133
134
135
136 }
137
138 int ans = isap(b,t) ;
139
140
141 //printf("%I64d %I64d +++++\n",sum , ans) ;
142 printf("%d\n",sum - ans) ;
143 }
144 }
2 #include<cstring>
3 #include<cmath>
4 #include<iostream>
5 #include<algorithm>
6 #include<set>
7 #include<map>
8 #include<queue>
9 #include<vector>
10 #include<string>
11 #define inf 0x7fffffff
12 #define maxn 60000
13 #define CL(a,b) memset(a,b,sizeof(a))
14
15 using namespace std;
16 struct node
17 {
18 int to;
19 int cap;
20 int next;
21 }p[maxn*10] ;
22 int dis[maxn],gap[maxn] ,cnt,next[maxn],s,e;// dis[i]为 到达 原点的层数
23 int n , m,NN ;//NN 为 加完点 之后的 总结点数
24 void add(int from,int to,int cap)//加 的 是 有向边
25 {
26 p[cnt].to = to;
27 p[cnt].cap = cap ;
28 p[cnt].next = next[from];
29 next[from] = cnt++;
30
31 p[cnt].to = from;
32 p[cnt].cap = 0;
33 p[cnt].next = next[to];
34 next[to] = cnt++ ;
35 }
36 int dfs(int pos,int cost)
37 {
38
39 if(pos == e)
40 return cost ;
41
42 int i,j ,mdis = NN ,f = cost ;
43
44 for(i = next[pos];i != - 1; i = p[i].next)
45 {
46 int to = p[i].to ;
47 int cap = p[i].cap ;
48 if(cap > 0 )
49 {
50 if(dis[to] + 1 == dis[pos])
51 {
52
53
54 int d = min(f,cap) ;// 注意 这 为 剩余 流量 和 cap 的 最小值
55
56 d = dfs(to,d) ;
57 p[i].cap -=d;
58 p[i^1].cap +=d;
59 f -= d;
60
61 if(dis[s] >= NN) return cost - f;// 如果没有 了 增广路经 结束算法
62 if(f == 0) break ;
63 }
64 if( dis[to] < mdis ) mdis = dis[to] ;// 记录可扩展的最小的狐
65
66 }
67
68 }
69 if(f == cost)// 没有 可以 扩展的点
70 {
71 --gap[dis[pos]];
72 if(gap[dis[pos]] == 0)dis[s] = NN;// 注意这 ,若 距离 为 dis[pos] 这一层都没有 扩展点了(断层) dis[s] = n
73
74 dis[pos] = mdis + 1;//维护距离标号的方法是这样的:当找增广路过程中发现某点出发没有允许弧时,将这个点的距离标号设为由它出发的所有弧的终点的距离标号的最 小值加一
75
76 ++gap[dis[pos]] ;
77 }
78 return cost - f ;
79 }
80 int isap( int b,int t)
81 {
82
83 int ret = 0;
84 s = b;
85 e = t;
86 CL(gap,0);
87 CL(dis,0) ;
88 gap[s] = NN ;//NN 为 加完点 之后的 总结点数
89 while(dis[s] < NN)
90 {
91 ret+=dfs(s,inf) ;
92 }
93 return ret ;
94
95 }
96 int a[maxn] ;
97 int main()
98 {
99 //read() ;
100 int i, x,y;
101 int d ;
102 while(scanf("%d%d",&n,&m)!=EOF)
103 {
104 int sum = 0 ;
105
106 CL(next, -1);
107
108
109 cnt = 0 ;
110 int b = 0 ;
111 int t = n + m + 1 ;
112 NN = n + m + 2;
113 for(i = 1; i <= n;i++)
114 {
115 scanf("%d",&a[i]) ;
116 add(i,t,a[i]) ;
117 }
118
119
120 for(i = 1 ; i <= m;i++)
121 {
122 scanf("%d%d%d",&x,&y,&d);
123
124 add(b,n+i,d) ;
125
126 sum += d ;
127
128 add(n + i,x,inf) ;
129
130
131 add(n + i ,y,inf) ;
132
133
134
135
136 }
137
138 int ans = isap(b,t) ;
139
140
141 //printf("%I64d %I64d +++++\n",sum , ans) ;
142 printf("%d\n",sum - ans) ;
143 }
144 }