P2764 最小路径覆盖问题

题目描述

«问题描述:

给定有向图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 }


原文地址:https://www.cnblogs.com/qldabiaoge/p/8994175.html