网络流最小路径覆盖

Posted 王宜鸣

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流最小路径覆盖相关的知识,希望对你有一定的参考价值。

思路:

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 }

 

以上是关于网络流最小路径覆盖的主要内容,如果未能解决你的问题,请参考以下文章

[网络流24题] 最小路径覆盖问题

网络流24题之 1738: 最小路径覆盖问题

P2764 最小路径覆盖问题 网络流输出方案

网络流24题 最小路径覆盖问题

网络流24题 #03最小路径覆盖问题

最小路径覆盖问题(网络流,二分图) & 最小路径点覆盖结论证明