[关闭]
@LinKArftc 2015-09-04T02:23:05.000000Z 字数 3406 阅读 1229

网络流

图论


最大流

一般增广路算法——Ford-Fulkerson(标号法)

复杂度

O(nmU)

Demo

  1. const int inf = 0x3f3f3f3f;
  2. const int maxn = 1010;
  3. struct Edge {
  4. int c, f;
  5. } edge[maxn][maxn];
  6. int n, m;
  7. int vis[maxn], prev[maxn], alpha[maxn];
  8. void ford() {
  9. while (1) {
  10. memset(vis, 0, sizeof(vis));
  11. vis[0] = 1;
  12. prev[0] = 0;
  13. alpha[0] = inf;
  14. queue <int> q;
  15. q.push(0);
  16. while (!q.empty() && !vis[n-1]) {
  17. int u = q.front();
  18. q.pop();
  19. for (int v = 0; v < n; v ++) {
  20. if (!vis[v]) {
  21. if (edge[u][v].c < inf && edge[u][v].f < edge[u][v].c) {//用edge[u][v].c < inf表示u,c之间有边
  22. vis[v] = 1;
  23. prev[v] = u;
  24. alpha[v] = min(alpha[u], edge[u][v].c - edge[u][v].f);
  25. q.push(v);
  26. } else if (edge[v][u].c < inf && edge[v][u].f > 0) {
  27. vis[v] = 1;
  28. prev[v] = -u;
  29. alpha[v] = min(alpha[u], edge[v][u].f);
  30. q.push(v);
  31. }
  32. }
  33. }
  34. }
  35. if (!vis[n-1] || alpha[n-1] == 0) break;
  36. int k1 = n - 1;
  37. int k2 = abs(prev[k1]);
  38. int a = alpha[n-1];
  39. while (1) {
  40. if (edge[k2][k1].f < inf) edge[k2][k1].f += a;
  41. else edge[k1][k2].f -= a;
  42. if (k2 == 0) break;
  43. k1 = k2;
  44. k2 = abs(prev[k1]);
  45. }
  46. }
  47. int max_flow = 0;
  48. for (int i = 0; i < n; i ++) {
  49. for (int j = 0; j < n; j ++) {
  50. if (i == 0 && edge[i][j].f < inf) max_flow += edge[i][j].f;
  51. if (edge[i][j].f < inf) printf("%d->%d : %d\n", i, j, edge[i][j].f);
  52. }
  53. }
  54. printf("max_flow : %d\n", max_flow);
  55. }
  56. int main() {
  57. int u, v, c, f;
  58. scanf("%d %d", &n, &m);
  59. memset(edge, 0x3f, sizeof(edge));
  60. for (int i = 0; i < m; i ++) {
  61. scanf("%d %d %d %d", &u, &v, &c, &f);
  62. edge[u][v].c = c;
  63. edge[u][v].f = f;
  64. }
  65. ford();
  66. return 0;
  67. }
  68. /*
  69. input:
  70. 6 10
  71. 0 1 8 2
  72. 0 2 4 3
  73. 1 3 2 2
  74. 1 4 2 2
  75. 2 1 4 2
  76. 2 3 1 1
  77. 2 4 4 0
  78. 3 4 6 0
  79. 3 5 9 3
  80. 4 5 7 2
  81. output:
  82. 0->1 : 4
  83. 0->2 : 4
  84. 1->3 : 2
  85. 1->4 : 2
  86. 2->1 : 0
  87. 2->3 : 1
  88. 2->4 : 3
  89. 3->4 : 0
  90. 3->5 : 3
  91. 4->5 : 5
  92. max_flow : 8
  93. */

例题

POJ 1149 PIGS

题意
迈克在一个养猪场工作,养猪场里有M 个猪圈,每个猪圈都上了锁。由于迈克没有钥匙,所以他不能打开任何一个猪圈。要买猪的顾客一个接一个来到养猪场,每个顾客有一些猪圈的钥匙,而且他们要买一定数量的猪。某一天,所有要到养猪场买猪的顾客,他们的信息是要提前让迈克知道的。这些信息包括:顾客所拥有的钥匙(详细到有几个猪圈的钥匙、有哪几个猪圈的钥匙)、要购买的数量。这样对迈克很有好处,他可以安排销售计划以便卖出的猪的数目最大。
更详细的销售过程:当每个顾客到来时,他将那些他拥有钥匙的猪圈全部打开;迈克从这些猪圈中挑出一些猪卖给他们;如果迈克愿意,迈克可以重新分配这些被打开的猪圈中的猪;当顾客离开时,猪圈再次被锁上。注意:猪圈可容纳的猪的数量没有限制。
求迈克这一天能卖出猪的最大数目。
输入
1) 第一行是两个整数:M 和N(1≤M≤1000,1≤N≤100)。M 是猪圈的数目,N 是顾客的数目。猪圈的编号从1 到M,顾客的编号从1 到N。
2) 第二行是M 个整数,为每个猪圈中初始时猪的数目,范围是[0,1000]。
3) 接下来的N 行是顾客的信息,第i 个顾客的信息保存在第i+2 行。格式为:A K1 K2…KA
B。A 为拥有钥匙的数目,Kj 表示拥有第Kj 个猪圈的钥匙,B 为该顾客想买的猪的数目。
A,B 均可为0。
输出
输出有且仅有一行,为迈克能够卖掉的猪的最大数目。

思路

  • 将顾客看作除源点和汇点以外的结点,另设 2 个结点:源点和汇点;
  • 源点和每个猪圈的第一个顾客连边,边的权是开始时猪圈中猪的数目;
  • 若源点和某个结点之间有重边,则将权合并(因此源点流出的流量就是所有的猪圈能提供的猪的数目);
  • 顾客j 紧跟在顾客i 之后打开某个猪圈,则边的权是+∞;这是因为,如果顾客j 紧跟在顾客i 之后打开某个猪圈,那么迈克就有可能根据顾客j 的需求将其他猪圈中的猪调整到该猪圈,这样顾客j 就能买到尽可能多的猪;
  • 每个顾客和汇点之间连边,边的权是顾客所希望购买的猪的数目(因此汇点的流入量就是每个顾客所购买的猪的数目)。

AC代码

  1. const int inf = 0x3f3f3f3f;
  2. const int maxm = 1005;
  3. const int maxn = 1005;//不知道为什么换成105就RE了= =||
  4. int s, t;
  5. int c[maxn][maxn];
  6. int flow[maxn][maxn];
  7. int num[maxm];
  8. int buy[maxn];
  9. int prev[maxn];
  10. int alpha[maxn];
  11. int vis[maxn];
  12. int m, n;
  13. void init() {
  14. while (~scanf("%d %d", &m, &n)) {//m个猪圈,n位顾客
  15. memset(c, 0, sizeof(c));
  16. memset(vis, 0, sizeof(vis));
  17. s = 0;
  18. t = n + 1;
  19. for (int i = 1; i <= m; i ++) scanf("%d", &num[i]);
  20. for (int i = 1; i <= n; i ++) {
  21. int key;
  22. scanf("%d", &key);
  23. for (int j = 1; j <= key; j ++) {
  24. int key_id;
  25. scanf("%d", &key_id);
  26. if (vis[key_id]) c[vis[key_id]][i] = inf;
  27. else c[s][i] += num[key_id];
  28. vis[key_id] = i;
  29. }
  30. scanf("%d", &c[i][t]);
  31. }
  32. }
  33. }
  34. void ford() {
  35. memset(flow, 0, sizeof(flow));
  36. while (1) {
  37. memset(vis, 0, sizeof(vis));
  38. vis[s] = 1;
  39. prev[s] = s;
  40. alpha[s] = inf;
  41. queue <int> q;
  42. q.push(s);
  43. while (!q.empty() && !vis[t]) {
  44. int u = q.front();
  45. q.pop();
  46. for (int v = s; v <= t; v ++) {
  47. if (!vis[v]) {
  48. if (c[u][v] && flow[u][v] < c[u][v]) {
  49. vis[v] = 1;
  50. prev[v] = u;
  51. alpha[v] = min(alpha[u], c[u][v] - flow[u][v]);
  52. q.push(v);
  53. } else if (c[v][u] && flow[v][u] > 0) {
  54. vis[v] = 1;
  55. prev[v] = -u;
  56. alpha[v] = min(alpha[u], flow[v][u]);
  57. q.push(v);
  58. }
  59. }
  60. }
  61. }
  62. if (!vis[t] || alpha[t] == 0) break;
  63. int k1 = t;
  64. int k2 = abs(prev[k1]);
  65. int a = alpha[t];
  66. while (1) {
  67. if (c[k2][k1]) flow[k2][k1] += a;
  68. else flow[k1][k2] -= a;
  69. if (k2 == 0) break;
  70. k1 = k2;
  71. k2 = abs(prev[k1]);
  72. }
  73. }
  74. int max_flow = 0;
  75. for (int i = 1; i <= n; i ++) {
  76. if (flow[s][i]) max_flow += flow[s][i];
  77. }
  78. printf("%d\n", max_flow);
  79. }
  80. int main() {
  81. init();
  82. ford();
  83. return 0;
  84. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注