题目描述
«问题描述:
给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。提示:设V={1,2,.... ,n},构造网络G1=(V1,E1)如下:
每条边的容量均为1。求网络G1的( 0 x , 0 y )最大流。
«编程任务:
对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。
输入输出格式
输入格式:
件第1 行有2个正整数n和m。n是给定有向无环图G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数i和j,表示一条有向边(i,j)。
输出格式:
从第1 行开始,每行输出一条路径。文件的最后一行是最少路径数。
输入输出样例
输入样例#1: 复制
11 12 1 2 1 3 1 4 2 5 3 6 4 7 5 8 6 9 7 10 8 11 9 11 10 11
输出样例#1: 复制
1 4 7 10 11 2 5 8 3 6 9 3
这题是一个网络流常用模型,
最小路径覆盖问题;
这题反向思考,就是点的数目-最大的二分匹配;
就是最少的路径数目;
这题算出最小路径,直接套网络流模板就行了;
但是要输出路径这就很恶心了;
我放弃了我自己原来的网络流模板;
找了一个更加适合输出路径的代码;
输出路径真心恶心
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 #define inf 0x3fffffff 7 using namespace std; 8 const int maxn = 1e5 + 10; 9 int head[maxn], sign, cur[maxn]; 10 int s, t, d[maxn]; 11 struct node { 12 int to, w, next; 13 } edge[maxn] ; 14 void creat() { 15 memset(head, -1, sizeof(head)); 16 sign = 0; 17 } 18 void add(int u, int v, int w) { 19 edge[sign].to = v; 20 edge[sign].w = w; 21 edge[sign].next = head[u]; 22 head[u] = sign++; 23 edge[sign].to = u; 24 edge[sign].w = 0; 25 edge[sign].next = head[v]; 26 head[v] = sign++; 27 } 28 int bfs() { 29 queue<int>q; 30 memset(d, 0, sizeof(d)); 31 d[s] = 1; 32 q.push(s); 33 while(!q.empty()) { 34 int top = q.front(); 35 q.pop(); 36 for (int i = head[top] ; ~i ; i = edge[i].next ) { 37 int to = edge[i].to; 38 if (edge[i].w > 0 && d[to] == 0) { 39 d[to] = d[top] + 1; 40 if (to == t) return 1; 41 q.push(to); 42 } 43 } 44 } 45 return d[t] != 0; 46 } 47 int dfs(int top, int flow ) { 48 if (top == t) return flow; 49 int ans = 0, x = 0; 50 for (int i = cur[top] ; ~i ; i = edge[i].next) { 51 int to = edge[i].to; 52 if (edge[i].w > 0 && d[to] == d[top] + 1) { 53 x = dfs(to, min(flow - ans, edge[i].w)) ; 54 edge[i].w -= x; 55 edge[i ^ 1].w += x; 56 if (edge[i].w) cur[top] = i; 57 ans += x; 58 if (ans == flow) return flow; 59 } 60 } 61 if (ans == 0) return d[top] = 0; 62 return ans; 63 } 64 65 int dinic(int n) { 66 int ans = 0; 67 while(bfs()) { 68 for (int i = 0 ; i <= n ; i++) 69 cur[i] = head[i]; 70 ans += dfs(s, inf); 71 } 72 return ans; 73 } 74 int n, m, vis[maxn]; 75 void go(int x, int &f) { 76 int loc = x + n; 77 vis[x] = 1; 78 for (int i = head[loc] ; ~i ; i = edge[i].next) 79 if (edge[i].w == 1 && edge[i].to != n * 2 + 1) go(edge[i].to, f) ; 80 if (f == 1) f = 0; 81 printf(" "); 82 printf("%d", x); 83 } 84 int main() { 85 scanf("%d%d", &n, &m); 86 creat(); 87 s = 0, t = 2 * n + 1; 88 for (int i = 1 ; i <= n ; i++) 89 add(s, i, 1), add(i + n, t, 1); 90 int x, y; 91 while(m--) { 92 scanf("%d%d", &x, &y); 93 add(x, y + n, 1); 94 } 95 int ans = n - dinic(t); 96 for (int i = head[t]; ~i ; i = edge[i].next) { 97 if (edge[i].w == 1 && !vis[edge[i].to - n]) { 98 int f = 1; 99 go(edge[i].to - n, f); 100 printf(" "); 101 } 102 } 103 printf("%d ", ans); 104 return 0; 105 }