hdu 4289 Control (最大流 最小割 成都赛区 网络赛)
http://acm.hdu.edu.cn/showproblem.php?pid=4289
题意: 有n个城市,有个小偷想从其中一个城市逃到另一个城市,警察想要堵截这个小偷,知道了在每个城市堵截的成本,问如何安排在哪些城市堵截可以使得
小偷一定会被抓住,而且成本最低。
题解 : 最大流 ; 将每一个点 查分成两个 ,x 和x+n 他们之间的流量为 在 x 点的花费 ,对于 右边相连的x,y l连接 x +n 到 y 和 y +n到 x 流量值 为 inf ,(这样保证了 流量 只受拆点边的限制) 最后 求 s 到 e+n 的 最值 即可
dinic 算法:
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 F(x) (x)
13 #define N(x) (205+(x))
14 #define CPN(x) (410+(x))
15 #define D(x) (615+(x))
16 #define maxn 420
17 #define CL(a,b) memset(a,b,sizeof(a))
18
19 using namespace std;
20
21 int next[maxn],dis[maxn];
22 int s,e;
23 int n, m,cnt,a[maxn];
24 struct node
25 {
26 int to;
27 int cap ;
28 int next ;
29 }p[200000] ;
30 void add(int x,int y,int cap)
31 {
32 p[cnt].to = y;
33 p[cnt].cap = cap ;
34 p[cnt].next = next[x];
35 next[x] = cnt++ ;
36
37 p[cnt].to = x;
38 p[cnt].cap = 0;
39 p[cnt].next = next[y];
40 next[y] = cnt++ ;
41 }
42 int bfs()// 重新 建 图 (按 层数 建图)
43 {
44
45 memset(dis,-1,sizeof(dis)) ;
46 dis[s] = 0 ;
47 queue<int>que;
48 que.push(s);
49
50 while(!que.empty())
51 {
52
53
54 int k = que.front();que.pop() ;
55 for( int i = next[k];i!=-1;i = p[i].next)
56 {
57 int v = p[i].to;
58
59
60 int cap = p[i].cap ;
61
62 if(cap > 0 && dis[v] < 0 )// 如果 可以 可以到达 但 还没有 访问
63 {
64
65 dis[v] = dis[k]+ 1 ;
66 que.push(v) ;
67 }
68 }
69
70 }
71
72
73 if(dis[e] > 0) return 1;
74 else return 0 ;
75
76 }
77
78
79
80 int dfs(int x,int mx)// 查找 路径上的 最小 的 流量
81 {
82
83 int i , a ,tf = 0;
84
85 if(x == e) return mx ;
86
87 for(i = next[x];i!= - 1;i = p[i].next)
88 {
89 int v = p[i].to ;
90 int cap = p[i].cap ;
91 if(cap > 0 && dis[v] == dis[x] + 1 && (a =dfs(v,min(cap,mx))))
92 {
93
94 p[i].cap -= a;
95 p[i^1].cap += a;
96
97 return a;
98
99
100 }
101 }
102 if(!tf) dis[x] = -1;// 没有 找到 最小流量 ,说明 从这个点到不了 终点 ,所以 标记一下
103 return tf ;
104 }
105
106
107
108
109
110 int main()
111 {
112 int i , j ,x,y;
113 int a;
114 //freopen("data.txt","r",stdin) ;
115 while(scanf("%d%d%d%d",&n,&m,&s,&e)!=EOF)
116 {
117
118 CL(next,-1) ;
119 cnt = 0;
120 // scanf("%d%d",&s,&e);
121 for(i = 1 ; i <= n;i++)
122 {
123 scanf("%d",&a) ;
124 add(i,i+n,a);
125 }
126
127
128 for(i = 0 ;i< m;i++)
129 {
130 scanf("%d%d",&x,&y);
131
132 add(x+n,y,INF) ;
133 add(y + n ,x,INF) ;
134 }
135
136 e = e + n;
137
138
139 int ans = 0;
140 int res;
141
142 while(bfs())
143 {
144
145
146 while(res = dfs(s,INF)) ans+= res ;
147
148 }
149 printf("%d\n",ans);
150 }
151 }
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 F(x) (x)
13 #define N(x) (205+(x))
14 #define CPN(x) (410+(x))
15 #define D(x) (615+(x))
16 #define maxn 420
17 #define CL(a,b) memset(a,b,sizeof(a))
18
19 using namespace std;
20
21 int next[maxn],dis[maxn];
22 int s,e;
23 int n, m,cnt,a[maxn];
24 struct node
25 {
26 int to;
27 int cap ;
28 int next ;
29 }p[200000] ;
30 void add(int x,int y,int cap)
31 {
32 p[cnt].to = y;
33 p[cnt].cap = cap ;
34 p[cnt].next = next[x];
35 next[x] = cnt++ ;
36
37 p[cnt].to = x;
38 p[cnt].cap = 0;
39 p[cnt].next = next[y];
40 next[y] = cnt++ ;
41 }
42 int bfs()// 重新 建 图 (按 层数 建图)
43 {
44
45 memset(dis,-1,sizeof(dis)) ;
46 dis[s] = 0 ;
47 queue<int>que;
48 que.push(s);
49
50 while(!que.empty())
51 {
52
53
54 int k = que.front();que.pop() ;
55 for( int i = next[k];i!=-1;i = p[i].next)
56 {
57 int v = p[i].to;
58
59
60 int cap = p[i].cap ;
61
62 if(cap > 0 && dis[v] < 0 )// 如果 可以 可以到达 但 还没有 访问
63 {
64
65 dis[v] = dis[k]+ 1 ;
66 que.push(v) ;
67 }
68 }
69
70 }
71
72
73 if(dis[e] > 0) return 1;
74 else return 0 ;
75
76 }
77
78
79
80 int dfs(int x,int mx)// 查找 路径上的 最小 的 流量
81 {
82
83 int i , a ,tf = 0;
84
85 if(x == e) return mx ;
86
87 for(i = next[x];i!= - 1;i = p[i].next)
88 {
89 int v = p[i].to ;
90 int cap = p[i].cap ;
91 if(cap > 0 && dis[v] == dis[x] + 1 && (a =dfs(v,min(cap,mx))))
92 {
93
94 p[i].cap -= a;
95 p[i^1].cap += a;
96
97 return a;
98
99
100 }
101 }
102 if(!tf) dis[x] = -1;// 没有 找到 最小流量 ,说明 从这个点到不了 终点 ,所以 标记一下
103 return tf ;
104 }
105
106
107
108
109
110 int main()
111 {
112 int i , j ,x,y;
113 int a;
114 //freopen("data.txt","r",stdin) ;
115 while(scanf("%d%d%d%d",&n,&m,&s,&e)!=EOF)
116 {
117
118 CL(next,-1) ;
119 cnt = 0;
120 // scanf("%d%d",&s,&e);
121 for(i = 1 ; i <= n;i++)
122 {
123 scanf("%d",&a) ;
124 add(i,i+n,a);
125 }
126
127
128 for(i = 0 ;i< m;i++)
129 {
130 scanf("%d%d",&x,&y);
131
132 add(x+n,y,INF) ;
133 add(y + n ,x,INF) ;
134 }
135
136 e = e + n;
137
138
139 int ans = 0;
140 int res;
141
142 while(bfs())
143 {
144
145
146 while(res = dfs(s,INF)) ans+= res ;
147
148 }
149 printf("%d\n",ans);
150 }
151 }
isap 算法:
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 500
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[200000] ;
22 int dis[maxn],gap[maxn] ,cnt,next[maxn],s,e;
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[0] = NN ;
89 while(dis[s] < NN)
90 {
91 ret+=dfs(s,INF) ;
92 }
93 return ret ;
94
95 }
96 int main()
97 {
98 int i,x,y,a,b,t;
99 //freopen("data.txt","r",stdin) ;
100 while(scanf("%d%d%d%d",&n,&m,&b,&t)!=EOF)
101 {
102 CL(next,-1);
103 cnt = 0 ;
104 NN = 2*n ;//NN 为 加完点 之后的 总结点数
105 for(i = 1;i <=n;i++)
106 {
107 scanf("%d",&a);
108 add(i,i+n,a) ;
109 }
110 for(i = 0; i<m;i++)
111 {
112 scanf("%d%d",&x,&y);
113 add(x+n,y,INF);
114 add(y + n,x,INF);
115 }
116
117 int ans = isap(b,t + n) ;
118 printf("%d\n",ans) ;
119 }
120 }
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 500
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[200000] ;
22 int dis[maxn],gap[maxn] ,cnt,next[maxn],s,e;
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[0] = NN ;
89 while(dis[s] < NN)
90 {
91 ret+=dfs(s,INF) ;
92 }
93 return ret ;
94
95 }
96 int main()
97 {
98 int i,x,y,a,b,t;
99 //freopen("data.txt","r",stdin) ;
100 while(scanf("%d%d%d%d",&n,&m,&b,&t)!=EOF)
101 {
102 CL(next,-1);
103 cnt = 0 ;
104 NN = 2*n ;//NN 为 加完点 之后的 总结点数
105 for(i = 1;i <=n;i++)
106 {
107 scanf("%d",&a);
108 add(i,i+n,a) ;
109 }
110 for(i = 0; i<m;i++)
111 {
112 scanf("%d%d",&x,&y);
113 add(x+n,y,INF);
114 add(y + n,x,INF);
115 }
116
117 int ans = isap(b,t + n) ;
118 printf("%d\n",ans) ;
119 }
120 }