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 }