平面图网络流
首先推荐一个论文:周冬2008年集训队论文《浅析最大最小定理在信息学竞赛中的应用》
论文说的很详细,然后再写写我的总结吧。
首先先说说什么是平面图,或者说平面图的性质:
- (欧拉公式)如果一个连通的平面图有n个点,m条边和f个面,那么f = m - n + 2。
- 每个平面图G都有一个与其对偶的平面图G*。
- G*中的每个点对应G中的一个面
- 对于G中的每条边e,e属于俩个面f1,f2,加入边(f1*, f2*),e只属于一个面,加入回边(f*, f*)
然后说说平面图G与其对偶图G*的关系:
- G的面数等于G*的点数,G*的点数等于G到面数,G与G*边数相等。
- G*中的环与G中的割一一对应。如下图:
s-t平面图最大流的快速求法:
连接s-t得到一个附加面
求该图的对偶图G*,令附加面对应的点为s*,无界面对应的点为t*。
删去s*和t*间的边。这时一条s*到t*的一条路径就对应了s-t的一条割。更进一步,如果我们令每条边的长度等于它的容量,那么最小割的容量就等于最短路径的长度。
相关题目:
- HDU3870 Catch the Theves:题意描述:一群贼,要从城市A(1,1)到城市B(n,n)作案,警察需要在贼到达B之前将其逮捕,所以要安排警力去守住某些路,然后需要给警察付费,每段路的需要付的费可以不同,然后给出一个矩阵表示g[i][j]表示从城市(i,j)到(i+1,j)和(i,j+1)需要付给警察的费用,题目求最少的钱能够使所有的贼被抓?裸的平面图最大流。。。做法见上面描述。我傻逼最短路加边的时候加成单项的了。。wa了好多次。代码君:
-
View Code
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 #include <vector> 6 #include <iostream> 7 using namespace std; 8 9 const int maxn = 405 * 405; 10 const int maxm = 4 * maxn; 11 const int inf = 0x3f3f3f3f; 12 int test, n, mp[444][444]; 13 14 struct Dijkstra { 15 typedef pair<long long, int> T; 16 vector<T> E[maxn]; 17 priority_queue<T, vector<T>, greater<T> > q; 18 int d[maxn], cnt; 19 20 void clearEdge() { 21 for (int i = 0; i < maxn; i++) 22 E[i].clear(); 23 } 24 25 void addEdge(int u, int v, int w) { 26 E[u].push_back(T(w, v)); 27 E[v].push_back(T(w, u)); 28 } 29 30 void dijkstra(int s) { 31 for (int i = 0; i < maxn; i++) 32 d[i] = inf; 33 cnt = 0; 34 while (!q.empty()) q.pop(); 35 int u, v, du, dv; 36 d[s] = 0; q.push(T(0, s)); 37 while (!q.empty()) { 38 u = q.top().second; 39 du = q.top().first; 40 q.pop(); 41 if (d[u] != du) continue; 42 for (vector<T>::iterator it = E[u].begin(); it != E[u].end(); it++) { 43 v = it->second; dv = du + it->first; 44 if (d[v] > dv) { 45 d[v] = dv; q.push(T(dv, v)); 46 } 47 } 48 } 49 } 50 }; 51 Dijkstra g; 52 53 int main() { 54 scanf("%d", &test); 55 for (int cas = 1; cas <= test; cas++) { 56 scanf("%d", &n); g.clearEdge(); 57 for (int i = 1; i <= n; i++) 58 for (int j = 1; j <= n; j++) 59 scanf("%d", &mp[i][j]); 60 int s = 0, t = (n-1) * (n-1) + 1; 61 for (int i = 1; i < n; i++) { 62 //printf("%d %d %lld\n", s, i, mp[1][i]); 63 g.addEdge(s, i, mp[1][i]); 64 //printf("%d %d %lld\n", s, (n-1)*i, mp[i][n]); 65 g.addEdge(s, (n-1)*i, mp[i][n]); 66 //printf("%d %d %lld\n", 1+(n-1)*(i-1), t, mp[i][1]); 67 g.addEdge(1+(n-1)*(i-1), t, mp[i][1]); 68 //printf("%d %d %lld\n", (n-1)*(n-2)+i, t, mp[n][i]); 69 g.addEdge((n-1)*(n-2)+i, t, mp[n][i]); 70 } 71 for (int i = 1; i < n; i++) { 72 for (int j = 1; j < n; j++) { 73 if (i != n - 1) { 74 //printf("%d %d %lld\n", (i-1)*(n-1)+j, i*(n-1)+j, mp[i+1][j]); 75 g.addEdge((i-1)*(n-1)+j, i*(n-1)+j, mp[i+1][j]); 76 } 77 if (j != n - 1) { 78 //printf("%d %d %lld\n", (i-1)*(n-1)+j, (i-1)*(n-1)+j+1, mp[i][j+1]); 79 g.addEdge((i-1)*(n-1)+j, (i-1)*(n-1)+j+1, mp[i][j+1]); 80 } 81 } 82 } 83 g.dijkstra(s); 84 printf("%d\n", g.d[t]); 85 } 86 return 0; 87 }
-
HDU4280 坑。。。
-
POJ2922 坑。。。
-
BZOJ1001 [Beijing2006]狼抓兔子:中文题,就不描述题意了。。裸的平面图网络流。。。做法如上。。。不过请允许我吐槽一下出题人的节操。。尼玛 n 和 m 竟然可以为1。。所以这种情况要特判一下。嗯~又wa了好多次。。。代码君:
View Code -
BZOJ2007