1. 程式人生 > >網絡流最小路徑覆蓋

網絡流最小路徑覆蓋

queue print flow 個數 .net max n) pty pan

思路:

http://blog.csdn.net/tramp_1/article/details/52742572

每個點x拆成兩個點x和x‘,分別表示x作為前驅和作為後繼。若原圖中x和y有邊,向x和y‘加一條有向邊。如此構成二分圖,記此二分圖中作為前驅的節點集合為A,作為後繼的節點集合為B。跑最大匹配,沒有匹配的點的個數(n-最大匹配數)就是需要的最少的路徑條數。正確性:二分匹配可以保證每個點頂多只有一個前驅,並且頂多只有一個後繼,也就保證了每個點在且僅在一條路徑中。此外,在二分圖中,A中每個沒有匹配的頂點對應了一條路徑的終點。(類似地,B中每一個沒有匹配的頂點對應了一條路徑的起點。)最大二分匹配可以保證A(或B)中沒有匹配的點的數量最少,亦即路徑條數最少。

實現:

  1 #include <bits/stdc++.h>
  2 
  3 #define N (1000 + 2)
  4 #define M (N * N + 4 * N)
  5 
  6 typedef long long LL;
  7 
  8 using namespace std;
  9 
 10 struct edge 
 11 {
 12     int v, cap, next;
 13 };
 14 edge e[M];
 15 
 16 int head[N], level[N], cur[N];
 17 int num_of_edges;
 18 
 19
/* 20 * When there are multiple test sets, you need to re-initialize before each 21 */ 22 void dinic_init(void) 23 { 24 num_of_edges = 0; 25 memset(head, -1, sizeof(head)); 26 return; 27 } 28 29 int add_edge(int u, int v, int c1, int c2) 30 { 31 int& i = num_of_edges;
32 33 assert(c1 >= 0 && c2 >= 0 && c1 + c2 >= 0); // check for possibility of overflow 34 e[i].v = v; 35 e[i].cap = c1; 36 e[i].next = head[u]; 37 head[u] = i++; 38 39 e[i].v = u; 40 e[i].cap = c2; 41 e[i].next = head[v]; 42 head[v] = i++; 43 return i; 44 } 45 46 void print_graph(int n) 47 { 48 for (int u=0; u<n; u++) 49 { 50 printf("%d: ", u); 51 for (int i=head[u]; i>=0; i=e[i].next) 52 { 53 printf("%d(%d)", e[i].v, e[i].cap); 54 } 55 printf("\n"); 56 } 57 return; 58 } 59 60 /* 61 * Find all augmentation paths in the current level graph 62 * This is the recursive version 63 */ 64 int dfs(int u, int t, int bn) 65 { 66 if (u == t) return bn; 67 int left = bn; 68 for (int &i=cur[u]; i>=0; i=e[i].next) 69 { 70 int v = e[i].v; 71 int c = e[i].cap; 72 if (c > 0 && level[u]+1 == level[v]) 73 { 74 int flow = dfs(v, t, min(left, c)); 75 if (flow > 0) 76 { 77 e[i].cap -= flow; 78 e[i^1].cap += flow; 79 cur[u] = i; 80 left -= flow; 81 if (!left) break; 82 } 83 } 84 } 85 if (left > 0) level[u] = 0; 86 return bn - left; 87 } 88 89 bool bfs(int s, int t) 90 { 91 memset(level, 0, sizeof(level)); 92 level[s] = 1; 93 queue<int> q; 94 q.push(s); 95 while (!q.empty()) 96 { 97 int u = q.front(); 98 q.pop(); 99 if (u == t) return true; 100 for (int i=head[u]; i>=0; i=e[i].next) 101 { 102 int v = e[i].v; 103 if (!level[v] && e[i].cap > 0) 104 { 105 level[v] = level[u]+1; 106 q.push(v); 107 } 108 } 109 } 110 return false; 111 } 112 113 LL dinic(int s, int t) 114 { 115 LL max_flow = 0; 116 117 while (bfs(s, t)) 118 { 119 memcpy(cur, head, sizeof(head)); 120 max_flow += dfs(s, t, INT_MAX); 121 } 122 return max_flow; 123 } 124 125 int main() 126 { 127 dinic_init(); 128 int m, n, x, y; 129 cin >> m >> n; 130 for (int i = 0; i < m; i++) 131 { 132 cin >> x >> y; 133 add_edge(x, y + n, 1, 0); 134 } 135 for (int i = 1; i <= n; i++) 136 { 137 add_edge(0, i, 1, 0); 138 add_edge(i + n, 2 * n + 1, 1, 0); 139 } 140 int ans = dinic(0, 2 * n + 1); 141 cout << n - ans << endl; 142 return 0; 143 }

網絡流最小路徑覆蓋