UVa 563 - Crimewave (拆点 + 最大流 & EK)

题意

抢劫完N个银行后要逃跑,问能不能不碰头跑出去

思路

重点在于不能碰头,也就是不能走到同一点。

这个要怎么控制呢?

答:把一个点拆成两个点,一个入,一个出,入到出的流量为1.

这样一来只要有人走过,下一个人就走不了了。

这就是要拆点的原因。

至于详细的拆法,Titanium已经讲得很好了(http://www.cnblogs.com/scau20110726/archive/2012/12/20/2827177.html)

网上的版本都是数组版邻接表?我就来(tou)一(xia)个(lan)vector版吧

引用一下他的解释。

算法思路:对于给定的网格,行为S列为A,我们按行优先给所有点标号,从1到S*A。然后对每个点拆点,拆点后一个点变为两个点(那么总点数为2*S*A),在这里我把拆点后的两个点叫做“前点”和“后点”,对于坐标为(i,j)的点,拆点后“前点”的编号为u=(i-1)*A+j , “后点”的编号好v=u+S*A;

我们还要额外设置一个源点s,编号为0,一个汇点,编号为2*S*A+1。从源点s建有向边指向所有的银行,从所有网格边沿的点建有向边指向汇点t,另外网格内一个点要和它上下左右四个点建立无向边(也就是两条有向边)。数据很大,要用邻接表保存

问题就是,我们已经事先拆点了,原来的两个点(i,j)和(i,j+1)有连线那么拆点后怎么链接呢?

第一部分(一个点和它上下左右的四个点建边):从这个点的“后点”和四周的点的“前点”建有向边(因为用邻接表建图,所以所有的有向边都有反边,注意反边的容量为0)。

第二部分(源点和所有银行建边):源点s和所有银行的“前点”建有向边(还有反边)

第三部分(所有网格边沿的点和汇点建边):所有网格边沿的点的“后点”和汇点建有向边(还有反边)

因此

第一部分:两个点a,b之间会有四边有向边,一条是a点的“后点”指向b点的“前点”,一条是b点的“后点”指向a点的“前点”。这两条还附带两条反边所以一共四条

第二部分:源点和银行的“前点”有边,再附带一个反边

第三部分:网格边沿点的“后点”和汇点有边,再附带一个反边

所有边的容量都1(这样就起到了每个点只能用一次的效果),附带的反边容量当然是为0

建图后,直接EK,算最大流,最大流等于银行个数那么可以逃脱,不等(小于)就不可以

代码

  
  
  
  
  1. #include <cstdio>
  2. #include <stack>
  3. #include <set>
  4. #include <iostream>
  5. #include <string>
  6. #include <vector>
  7. #include <queue>
  8. #include <functional>
  9. #include <cstring>
  10. #include <algorithm>
  11. #include <cctype>
  12. #include <ctime>
  13. #include <cstdlib>
  14. #include <fstream>
  15. #include <string>
  16. #include <sstream>
  17. #include <map>
  18. #include <cmath>
  19. #define LL long long
  20. #define SZ(x) (int)x.size()
  21. #define Lowbit(x) ((x) & (-x))
  22. #define MP(a, b) make_pair(a, b)
  23. #define MS(arr, num) memset(arr, num, sizeof(arr))
  24. #define PB push_back
  25. #define F first
  26. #define S second
  27. #define ROP freopen("input.txt", "r", stdin);
  28. #define MID(a, b) (a + ((b - a) >> 1))
  29. #define LC rt << 1, l, mid
  30. #define RC rt << 1|1, mid + 1, r
  31. #define LRT rt << 1
  32. #define RRT rt << 1|1
  33. #define BitCount(x) __builtin_popcount(x)
  34. const double PI = acos(-1.0);
  35. const int INF = 0x3f3f3f3f;
  36. using namespace std;
  37. const int MAXN = 5100 + 10;
  38. const int MOD = 1e9 + 7;
  39. const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
  40. typedef pair<int, int> pii;
  41. typedef vector<int>::iterator viti;
  42. typedef vector<pii>::iterator vitii;
  43. struct EDGE
  44. {
  45. int from, to, cap, flow;
  46. };
  47. struct MAXFLOW
  48. {
  49. int a[MAXN], p[MAXN];
  50. vector<EDGE> edges;
  51. vector<int> G[MAXN];
  52. void init()
  53. {
  54. for (int i = 0; i < MAXN; i++) G[i].clear();
  55. edges.clear();
  56. }
  57. void add_edge(int from, int to, int cap)
  58. {
  59. edges.PB((EDGE){from, to, cap, 0});
  60. edges.PB((EDGE){to, from, 0, 0});
  61. int m = SZ(edges);
  62. G[from].PB(m - 2); G[to].PB(m - 1);
  63. }
  64. void EK(int st, int ed, int &flow)
  65. {
  66. queue<int> qu;
  67. while (true)
  68. {
  69. MS(a, 0);
  70. a[st] = INF;
  71. qu.push(st);
  72. while (!qu.empty())
  73. {
  74. int u = qu.front(); qu.pop();
  75. for (int i = 0; i < SZ(G[u]); i++)
  76. {
  77. EDGE &e = edges[G[u][i]];
  78. if (!a[e.to] && e.cap > e.flow)
  79. {
  80. a[e.to] = min(a[u], e.cap - e.flow);
  81. qu.push(e.to);
  82. p[e.to] = G[u][i];
  83. }
  84. }
  85. }
  86. if (!a[ed]) break;
  87. int u = ed;
  88. while (u != st)
  89. {
  90. edges[p[u]].flow += a[ed];
  91. edges[p[u] ^ 1].flow -= a[ed];
  92. u = edges[p[u]].from;
  93. }
  94. flow += a[ed];
  95. }
  96. }
  97. }maxFlow;
  98. int main()
  99. {
  100. //ROP;
  101. int T, i, j, n, m, nbank;
  102. scanf("%d", &T);
  103. while (T--)
  104. {
  105. maxFlow.init();
  106. scanf("%d%d%d", &n, &m, &nbank);
  107. int st = 0, ed = m * n * 2 + 1;
  108. for (i = 1; i <= n; i++)
  109. for (j = 1; j <= m; j++)
  110. {
  111. int u = (i - 1) * m + j; //入点
  112. int v = u + m * n; //出点
  113. maxFlow.add_edge(u, v, 1);
  114. for (int k = 0; k < 4; k++)
  115. {
  116. int ii = i + dir[k][0], jj = j + dir[k][1];
  117. if (ii >= 1 && ii <= n && jj >= 1 && jj <= m)
  118. {
  119. int uu = (ii - 1) * m + jj;
  120. maxFlow.add_edge(v, uu, 1);
  121. }
  122. else maxFlow.add_edge(v, ed, 1);
  123. }
  124. }
  125. for (i = 0; i < nbank; i++)
  126. {
  127. int a, b;
  128. scanf("%d%d", &a, &b);
  129. int u = (a - 1) * m + b;
  130. maxFlow.add_edge(st, u, 1);
  131. }
  132. int flow = 0;
  133. maxFlow.EK(st, ed, flow);
  134. printf("%s\n", (flow == nbank ? "possible" : "not possible"));
  135. }
  136. return 0;
  137. }

你可能感兴趣的:(ACM,uva)