Algorithm平面图最小割转最短路

Posted Bombe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(falseBZOJ1001: [BeiJing2006]狼抓兔子 (最小割转最短路)

bzoj 2007 [Noi2010]海拔——最小割转最短路

NOI 2010 海拔 ——平面图转对偶图

BZOJ 1001 狼抓兔子

B20J_2007_[Noi2010]海拔_平面图最小割转对偶图+堆优化Dij

BZOJ1001: [BeiJing2006]狼抓兔子