【Algorithm】平面图最小割转最短路

杭电上碰巧有几道求最小割的题目,用网络流解超时。
通过离散数学中的一些知识可以将平面图最小割转化为最短路径,通过最短路解提高效率。
这个转化过程很简单,但是很巧妙,详细内容可以参考《浅析最大最小定理在信息学竞赛中的应用》。

1. 【HDU】 3870 Catch the Theves
有一个网格拓扑,每条边都表示有$A_{ij}$个小偷,现在希望对其中一条边部署警察,使得小偷不可能偷到右下角的财宝。
求至少需要多少个警察?
这题是个挺有实际意义的题目,基本思路也很简单。
因为题目给定小偷都从左上角出发向右下角前进。显然可以对网格拓扑建网络流,然后解这个网络流,最小割就是所求解。
示意图如下:

$n \in [1, 400]$直接跑个网络流会超时,因此,我们构建对偶图,将问题转化。
实际,我们应该建立的是原图的对偶图,但是因为对偶图存在环,并且每个环都代表了一个割。
因此我们将环切开,将其分割为两个节点$st$和$ed$,故将问题转化为SSSP问题。新的示意图如下:

故,所有的难点就变成了如何建图。

  1 /* 3870 */
  2 #include <iostream>
  3 #include <sstream>
  4 #include <string>
  5 #include <map>
  6 #include <queue>
  7 #include <set>
  8 #include <stack>
  9 #include <vector>
 10 #include <deque>
 11 #include <bitset>
 12 #include <algorithm>
 13 #include <cstdio>
 14 #include <cmath>
 15 #include <ctime>
 16 #include <cstring>
 17 #include <climits>
 18 #include <cctype>
 19 #include <cassert>
 20 #include <functional>
 21 #include <iterator>
 22 #include <iomanip>
 23 using namespace std;
 24 //#pragma comment(linker,"/STACK:102400000,1024000")
 25 
 26 #define sti                set<int>
 27 #define stpii            set<pair<int, int> >
 28 #define mpii            map<int,int>
 29 #define vi                vector<int>
 30 #define pii                pair<int,int>
 31 #define vpii            vector<pair<int,int> >
 32 #define rep(i, a, n)     for (int i=a;i<n;++i)
 33 #define per(i, a, n)     for (int i=n-1;i>=a;--i)
 34 #define clr                clear
 35 #define pb                 push_back
 36 #define mp                 make_pair
 37 #define fir                first
 38 #define sec                second
 39 #define all(x)             (x).begin(),(x).end()
 40 #define SZ(x)             ((int)(x).size())
 41 #define lson            l, mid, rt<<1
 42 #define rson            mid+1, r, rt<<1|1
 43 
 44 typedef struct {
 45     int v, w, nxt;
 46 } edge_t;
 47 
 48 const int INF = 0x3f3f3f3f;
 49 const int maxn = 405;
 50 const int maxv = 160005;
 51 const int st = maxv - 1;
 52 const int ed = maxv - 2;
 53 const int maxe = maxv * 4;
 54 int head[maxv], l;
 55 edge_t E[maxe];
 56 int dis[maxv];
 57 bool visit[maxv];
 58 int cost[maxn][maxn];
 59 int n;
 60 
 61 void init() {
 62     memset(head, -1, sizeof(head));
 63     l = 0;
 64 }
 65 
 66 void addEdge(int u, int v, int w) {
 67     E[l].v = v;
 68     E[l].w = w;
 69     E[l].nxt = head[u];
 70     head[u] = l++;
 71 }
 72 
 73 void spfa() {
 74     queue<int> Q;
 75     int u, v, k;
 76     
 77     memset(visit, false, sizeof(visit));
 78     memset(dis, INF, sizeof(dis));
 79     Q.push(st);
 80     visit[st] = true;
 81     dis[st] = 0;
 82     
 83     while (!Q.empty()) {
 84         u = Q.front();
 85         Q.pop();
 86         visit[u] = false;
 87         for (k=head[u]; k!=-1; k=E[k].nxt) {
 88             v = E[k].v;
 89             if (dis[v] > dis[u]+E[k].w) {
 90                 dis[v] = dis[u] + E[k].w;
 91                 if (!visit[v]) {
 92                     visit[v] = true;
 93                     Q.push(v);
 94                 }
 95             }
 96         }
 97     }
 98 }
 99 
100 void solve() {
101     init();
102     int n_ = n - 1;
103     
104     rep(i, 0, n) {
105         rep(j, 0, n) {
106             if (i==0 && j!=n-1) {
107                 addEdge(st, i*n_+j, cost[i][j]);
108             }
109             if (j==n-1 && i!=n-1) {
110                 addEdge(st, i*n_+j-1, cost[i][j]);
111             }
112             if (j==0 && i!=n-1) {
113                 addEdge(i*n_+j, ed, cost[i][j]);
114             }
115             if (i==n-1 && j!=n-1) {
116                 addEdge((i-1)*n_+j, ed, cost[i][j]);
117             }
118             
119             if (i!=n-1 && j!=n-1) {
120                 if (i) {
121                     addEdge((i-1)*n_+j, i*n_+j, cost[i][j]);
122                     addEdge(i*n_+j, (i-1)*n_+j, cost[i][j]);
123                 }
124                 if (j) {
125                     addEdge(i*n_+j-1, i*n_+j, cost[i][j]);
126                     addEdge(i*n_+j, i*n_+j-1, cost[i][j]);
127                 }
128             }
129         }
130     }
131     
132     spfa();
133     printf("%d\n", dis[ed]);
134 }
135 
136 int main() {
137     ios::sync_with_stdio(false);
138     #ifndef ONLINE_JUDGE
139         freopen("data.in", "r", stdin);
140         freopen("data.out", "w", stdout);
141     #endif
142     
143     int t;
144     
145     scanf("%d", &t);
146     while (t--) {
147         scanf("%d", &n);
148         rep(i, 0, n)
149             rep(j, 0, n)
150                 scanf("%d", &cost[i][j]);
151         solve();
152     }
153     
154     #ifndef ONLINE_JUDGE
155         printf("time = %d.\n", (int)clock());
156     #endif
157     
158     return 0;
159 }
View Code


2. 【HDU】 3860 Circuit Board
基本方式类似,建图的trick更麻烦一点。

  1 /* 3860 */
  2 #include <iostream>
  3 #include <sstream>
  4 #include <string>
  5 #include <map>
  6 #include <queue>
  7 #include <set>
  8 #include <stack>
  9 #include <vector>
 10 #include <deque>
 11 #include <bitset>
 12 #include <algorithm>
 13 #include <cstdio>
 14 #include <cmath>
 15 #include <ctime>
 16 #include <cstring>
 17 #include <climits>
 18 #include <cctype>
 19 #include <cassert>
 20 #include <functional>
 21 #include <iterator>
 22 #include <iomanip>
 23 using namespace std;
 24 //#pragma comment(linker,"/STACK:102400000,1024000")
 25 
 26 #define sti                set<int>
 27 #define stpii            set<pair<int, int> >
 28 #define mpii            map<int,int>
 29 #define vi                vector<int>
 30 #define pii                pair<int,int>
 31 #define vpii            vector<pair<int,int> >
 32 #define rep(i, a, n)     for (int i=a;i<n;++i)
 33 #define per(i, a, n)     for (int i=n-1;i>=a;--i)
 34 #define clr                clear
 35 #define pb                 push_back
 36 #define mp                 make_pair
 37 #define fir                first
 38 #define sec                second
 39 #define all(x)             (x).begin(),(x).end()
 40 #define SZ(x)             ((int)(x).size())
 41 #define lson            l, mid, rt<<1
 42 #define rson            mid+1, r, rt<<1|1
 43 
 44 #define UP         0
 45 #define DOWN     1
 46 #define LEFT    2
 47 #define RIGHT    3
 48 
 49 typedef struct {
 50     int v, w, nxt;
 51 } edge_t;
 52 
 53 const int INF = 0x3f3f3f3f;
 54 const int maxn = 205;
 55 const int maxv = maxn * maxn;
 56 const int st = maxv - 1;
 57 const int ed = maxv - 2;
 58 const int maxe = maxv * 20;
 59 int head[maxv], l;
 60 edge_t E[maxe];
 61 int dis[maxv];
 62 bool visit[maxv];
 63 pii pp[maxn], op[maxn];
 64 int pn, on;
 65 int cap[maxv][4];
 66 int dir[4][2] = {
 67     -1,0,1,0,0,-1,0,1
 68 };
 69 int ID[maxn][maxn];
 70 int W[10005], wn;
 71 int n, m;
 72 
 73 inline bool judge(int x, int y) {
 74     return x>=0 && x<n && y>=0 && y<m;
 75 }
 76 
 77 int getDir(int x, int y, int xx, int yy) {
 78     rep(k, 0, 4) {
 79         if (xx==x+dir[k][0] && yy==y+dir[k][1])
 80             return k;
 81     }
 82     return -1;
 83 }
 84 
 85 void init() {
 86     memset(head, -1, sizeof(head));
 87     l = 0;
 88 }
 89 
 90 void addEdge(int u, int v, int w) {
 91     #ifndef ONLINE_JUDGE
 92         printf("u = %d, v = %d, w = %d\n", u, v, w);
 93     #endif
 94     E[l].v = v;
 95     E[l].w = w;
 96     E[l].nxt = head[u];
 97     head[u] = l++;
 98     
 99     E[l].v = u;
100     E[l].w = w;
101     E[l].nxt = head[v];
102     head[v] = l++;
103 }
104 
105 void spfa() {
106     queue<int> Q;
107     int u, v, k;
108     
109     memset(visit, false, sizeof(visit));
110     memset(dis, -1, sizeof(dis));
111     dis[st] = 0;
112     visit[st] = true;
113     Q.push(st);
114     
115     while (!Q.empty()) {
116         u = Q.front();
117         Q.pop();
118         visit[u] = false;
119         for (k=head[u]; k!=-1; k=E[k].nxt) {
120             v = E[k].v;
121             if (dis[v]==-1 || dis[v]>dis[u]+E[k].w) {
122                 dis[v] = dis[u]+E[k].w;
123                 if (!visit[v]) {
124                     visit[v] = true;
125                     Q.push(v);
126                 }
127             }
128         }
129     }
130 }
131 
132 void Build(int bound) {
133     int prel = n * m, prer = prel + pn-1;
134     
135     init();
136     
137     // handle power station
138     if (pn > 1) {
139         rep(i, 0, pn) {
140             if (i == 0) {
141                 addEdge(st, prel, pp[i].sec);
142             } else if (i == pn-1) {
143                 addEdge(prel+pn-2, ed, pp[i].sec);
144             } else {
145                 addEdge(prel+i-1, prel+i, pp[i].sec);
146                 
147                 int l = pp[i-1].fir;
148                 int r = pp[i].fir;
149                 rep(j, l, r) {
150                     int tmp = min(cap[ID[j][0]][DOWN], bound);
151                     addEdge(prel+i-1, ID[j][0], tmp);
152                 }
153             }
154         }
155     } else {
156         addEdge(st, ed, pp[0].sec);
157     }
158     
159     // handle terminal station
160     if (on > 1) {
161         rep(i, 0, on) {
162             if (i == 0) {
163                 addEdge(st, prer, op[i].sec);
164             } else if (i == on-1) {
165                 addEdge(prer+on-2, ed, op[i].sec);
166             } else {
167                 addEdge(prer+i-1, prer+i, op[i].sec);
168                 
169                 int l = op[i-1].fir;
170                 int r = op[i].fir;
171                 rep(j, l, r) {
172                     int tmp = min(cap[ID[j][m-1]][DOWN], bound);
173                     addEdge(prer+i-1, ID[j][m-2], tmp);
174                 }
175             }
176         }
177     } else {
178         addEdge(st, ed, op[0].sec);
179     }
180     
181     rep(j, 0, m-1) {
182         int tmp = min(cap[ID[0][j]][RIGHT], bound);
183         addEdge(st, ID[0][j], tmp);
184         
185         tmp = min(cap[ID[n-1][j]][RIGHT], bound);
186         addEdge(ed, ID[n-2][j], tmp);
187     }
188     
189     rep(i, 0, pp[0].fir) {
190         int tmp = min(cap[ID[i][0]][DOWN], bound);
191         addEdge(st, ID[i][0], tmp);
192     }
193     rep(i, 0, op[0].fir) {
194         int tmp = min(cap[ID[i][m-1]][DOWN], bound);
195         addEdge(st, ID[i][m-2], tmp);
196     }
197     rep(i, pp[pn-1].fir, n-1) {
198         int tmp = min(cap[ID[i][0]][DOWN], bound);
199         addEdge(ID[i][0], ed, tmp);
200     }
201     rep(i, op[on-1].fir, n-1) {
202         int tmp = min(cap[ID[i][m-1]][DOWN], bound);
203         addEdge(ID[i][m-1], ed, tmp);
204     }
205     
206     rep(i, 0, n-1) {
207         rep(j, 0, m-1) {
208             int tmp[4];
209             
210             tmp[UP] = min(cap[ID[i][j]][RIGHT], bound);
211             tmp[LEFT] = min(cap[ID[i][j]][DOWN], bound);
212             tmp[DOWN] = min(cap[ID[i+1][j+1]][LEFT], bound);
213             tmp[RIGHT] = min(cap[ID[i+1][j+1]][UP], bound);
214             
215             rep(k, 0, 4) {
216                 int ii = i + dir[k][0];
217                 int jj = j + dir[k][1];
218                 
219                 if (ii>=0 && ii<n-1 && jj>=0 && jj<m-1)
220                     addEdge(ID[i][j], ID[ii][jj], tmp[k]);
221             }
222         }
223     }
224     
225     #ifndef ONLINE_JUDGE
226         putchar('\n');
227     #endif
228 }
229 
230 void solve() {
231     int l = 0, r = wn - 1, mid;
232     int ans = -1;
233     int tot = 0;
234     
235     rep(i, 0, on)
236         tot += op[i].sec;
237     
238     while (l <= r) {
239         mid = (l + r) >> 1;
240         #ifndef ONLINE_JUDGE
241             // printf("bound = %d\n", W[mid]);
242         #endif
243         Build(W[mid]);
244         spfa();
245         if (dis[ed] >= tot) {
246             ans = W[mid];
247             r = mid - 1;
248         } else {
249             l = mid + 1;
250         }
251     }
252     
253     printf("%d\n", ans);
254 }
255 
256 int main() {
257     ios::sync_with_stdio(false);
258     #ifndef ONLINE_JUDGE
259         freopen("data.in", "r", stdin);
260         freopen("data.out", "w", stdout);
261     #endif
262     
263     int t;
264     
265     scanf("%d", &t);
266     while (t--) {
267         scanf("%d%d", &n,&m);
268         scanf("%d", &pn);
269         
270         // power station & terminal station
271         rep(i, 0, pn) {
272             scanf("%d%d", &pp[i].fir, &pp[i].sec);
273             --pp[i].fir;
274         }
275         scanf("%d", &on);
276         rep(i, 0, on) {
277             scanf("%d%d", &op[i].fir, &op[i].sec);
278             --op[i].fir;
279         }
280         sort(pp, pp+pn);
281         sort(op, op+on);
282         
283         // cap between adjancy points
284         int id = 0;
285         rep(i, 0, n) {
286             rep(j, 0, m) {
287                 rep(k, 0, 4) {
288                     if (judge(i+dir[k][0], j+dir[k][1]))
289                         cap[id][k] = INF;
290                     else
291                         cap[id][k] = 0;
292                 }
293                 ID[i][j] = id++;
294             }
295         }
296         
297         // cap has boundry
298         int q;
299         int x1, y1, x2, y2, tmp;
300         scanf("%d", &q);
301         while (q--) {
302             scanf("%d%d%d%d%d", &x1,&y1,&x2,&y2,&tmp);
303             --x1; --y1; --x2; --y2;
304             cap[ID[x1][y1]][getDir(x1,y1,x2,y2)] = tmp;
305             cap[ID[x2][y2]][getDir(x2,y2,x1,y1)] = tmp;
306         }
307         
308         // cap with destroyed point
309         scanf("%d", &q);
310         while (q--) {
311             scanf("%d%d", &x1,&y1);
312             --x1, --y1;
313             rep(k, 0, 4) {
314                 x2 = x1 + dir[k][0];
315                 y2 = y1 + dir[k][1];
316                 if (judge(x2, y2))
317                         cap[ID[x2][y2]][getDir(x2,y2,x1,y1)] = 0;
318             }
319         }
320         
321         // wire kind
322         scanf("%d", &wn);
323         rep(i, 0, wn)
324             scanf("%d", &W[i]);
325         sort(W, W+wn);
326         
327         solve();
328     }
329     
330     #ifndef ONLINE_JUDGE
331         printf("time = %d.\n", (int)clock());
332     #endif
333     
334     return 0;
335 }
View Code


3. 【HDU】 3035 War
这个和3870很类似,建图稍微复杂一点儿,强烈建议做3860,建图最为复杂。
示意图如下:

  1 /* 3035 */
  2 #include <iostream>
  3 #include <sstream>
  4 #include <string>
  5 #include <map>
  6 #include <queue>
  7 #include <set>
  8 #include <stack>
  9 #include <vector>
 10 #include <deque>
 11 #include <bitset>
 12 #include <algorithm>
 13 #include <cstdio>
 14 #include <cmath>
 15 #include <ctime>
 16 #include <cstring>
 17 #include <climits>
 18 #include <cctype>
 19 #include <cassert>
 20 #include <functional>
 21 #include <iterator>
 22 #include <iomanip>
 23 using namespace std;
 24 //#pragma comment(linker,"/STACK:102400000,1024000")
 25 
 26 #define sti                set<int>
 27 #define stpii            set<pair<int, int> >
 28 #define mpii            map<int,int>
 29 #define vi                vector<int>
 30 #define pii                pair<int,int>
 31 #define vpii            vector<pair<int,int> >
 32 #define rep(i, a, n)     for (int i=a;i<n;++i)
 33 #define per(i, a, n)     for (int i=n-1;i>=a;--i)
 34 #define clr                clear
 35 #define pb                 push_back
 36 #define mp                 make_pair
 37 #define fir                first
 38 #define sec                second
 39 #define all(x)             (x).begin(),(x).end()
 40 #define SZ(x)             ((int)(x).size())
 41 #define lson            l, mid, rt<<1
 42 #define rson            mid+1, r, rt<<1|1
 43 
 44 typedef struct {
 45     int v, w, nxt;
 46 } edge_t;
 47 
 48 typedef struct node_t {
 49     int v, w;
 50     
 51     node_t() {}
 52     node_t(int v, int w):
 53         v(v), w(w) {}
 54     
 55     friend bool operator< (const node_t& a, const node_t& b) {
 56         return a.w > b.w;
 57     }
 58     
 59 } node_t;
 60 
 61 const int INF = 0x3f3f3f3f;
 62 const int maxv = 1e6+15;
 63 const int maxe = 5e6+15;
 64 const int st = maxv - 1;
 65 const int ed = maxv - 2;
 66 int head[maxv], l;
 67 bool visit[maxv];
 68 int dis[maxv];
 69 edge_t E[maxe];
 70 int n, m;
 71 
 72 void init() {
 73     l = 0;
 74     memset(head, -1, sizeof(head));
 75 }
 76 
 77 void addEdge(int u, int v, int w) {
 78     #ifndef ONLINE_JUDGE
 79         // printf("u = %d, v = %d, w = %d\n", u, v, w);
 80     #endif
 81     E[l].v = v;
 82     E[l].w = w;
 83     E[l].nxt = head[u];
 84     head[u] = l++;
 85     
 86     E[l].v = u;
 87     E[l].w = w;
 88     E[l].nxt = head[v];
 89     head[v] = l++;    
 90 }
 91 
 92 void spfa() {
 93     priority_queue<node_t> Q;
 94     node_t nd;
 95     
 96     memset(visit, false, sizeof(visit));
 97     memset(dis, INF, sizeof(dis));
 98     Q.push(node_t(st, 0));
 99     dis[st] = 0;
100     
101     while (!Q.empty()) {
102         nd = Q.top();
103         Q.pop();
104         int& u = nd.v;
105         if (u == ed)
106             break;
107         if (visit[u])
108             continue;
109         
110         visit[u] = true;
111         for (int k=head[u]; k!=-1; k=E[k].nxt) {
112             int& v = E[k].v;
113             if (!visit[v] && dis[v]>dis[u]+E[k].w) {
114                 dis[v] = dis[u] + E[k].w;
115                 Q.push(node_t(v, dis[v]));
116             }
117         }
118     }
119 }
120 
121 void Build() {
122     int w, w1, w2;
123     
124     rep(j, 0, m) {
125         scanf("%d", &w);
126         addEdge(st, (j<<2)|1, w);
127     }
128     
129     rep(i, 0, n-1) {
130         rep(j, 0, m) {
131             scanf("%d", &w);
132             addEdge((i*m+j)<<2|3, ((i+1)*m+j)<<2|1, w);
133         }
134     }
135     
136     rep(j, 0, m) {
137         scanf("%d", &w);
138         addEdge(((n-1)*m+j)<<2|3, ed, w);
139     }
140     
141     rep(i, 0, n) {
142         scanf("%d", &w);
143         addEdge((i*m)<<2, ed, w);
144         rep(j, 0, m-1) {
145             scanf("%d", &w);
146             addEdge((i*m+j)<<2|2, (i*m+j+1)<<2, w);
147         }
148         scanf("%d", &w);
149         addEdge(st, (i*m+m-1)<<2|2, w);
150     }
151     
152     rep(i, 0, n) {
153         rep(j, 0, m) {
154             scanf("%d%d", &w1,&w2);
155             int base = (i*m+j)<<2;
156             addEdge(base, base|1, w1);
157             addEdge(base|1, base|2, w2);
158         }
159         rep(j, 0, m) {
160             scanf("%d%d", &w1,&w2);
161             int base = (i*m+j)<<2;
162             addEdge(base|3, base, w1);
163             addEdge(base|2, base|3, w2);
164         }
165     }
166 }
167 
168 void solve() {
169     init();
170     Build();
171     spfa();
172     printf("%d\n", dis[ed]);
173 }
174 
175 int main() {
176     ios::sync_with_stdio(false);
177     #ifndef ONLINE_JUDGE
178         freopen("data.in", "r", stdin);
179         freopen("data.out", "w", stdout);
180     #endif
181     
182     while (scanf("%d%d", &n, &m)!=EOF) {
183         solve();
184     }
185     
186     #ifndef ONLINE_JUDGE
187         printf("time = %d.\n", (int)clock());
188     #endif
189     
190     return 0;
191 }
View Code

 

posted on 2016-04-05 00:07  Bombe  阅读(1082)  评论(0编辑  收藏  举报

导航