洛谷 P2764 最小路径覆盖问题【最大流】

题目链接:https://www.luogu.org/problemnew/show/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<=n<=150,1<=m<=6000

由@zhouyonglong提供SPJ

 

题解:

  最小路径覆盖问题。答案就是N-最大二分匹配(证明略,感觉hihoCoder上讲的很详细,推荐看)。

  将每个点拆点分成AB两部分,做最大二分匹配。然后源点到A部的点连边,边权为1;B部点到汇点连边,边权为1,跑最大流......

  关于路径输出问题,可以从汇点开始找残余容量为0的点作为起始点递归输出路径...

代码:

  1 #include <cstdio>
  2 #include <vector>
  3 #include <algorithm>
  4 #include <queue>
  5 #include <cstring>
  6 using namespace std;
  7 const int N = 250*2+5;
  8 const int M = 6000*2+5;
  9 const int inf = 1e9;
 10 int n, m, S, T;
 11 int dep[N], cur[N];
 12 int head[N];
 13 struct Edge{
 14     int v, c, nex;
 15     Edge(int _v=0,int _c=0,int _nex=0):v(_v),c(_c),nex(_nex){}
 16 }E[M];
 17 
 18 int cnt;
 19 void add(int u, int v, int c){
 20     E[cnt].v = v;
 21     E[cnt].c = c;
 22     E[cnt].nex = head[u];
 23     head[u] = cnt++;
 24 }
 25 
 26 bool bfs() {
 27     queue<int> q;
 28     memset(dep, -1, sizeof(dep));
 29     q.push(S); dep[S] = 0;
 30     while(!q.empty()) {
 31         int u = q.front(); q.pop();
 32         for(int i = head[u]; ~i; i = E[i].nex) {
 33             int v = E[i].v;
 34             if(E[i].c && dep[v] == -1) {
 35                 dep[v] = dep[u] + 1;
 36                 q.push(v);
 37             }
 38         }
 39     }
 40     return dep[T] != -1;
 41 }
 42 int dfs(int u, int flow) {
 43     if(u == T) return flow;
 44     int w, used=0;
 45     for(int i = head[u]; ~i; i = E[i].nex) {
 46         int v = E[i].v;
 47         if(dep[v] == dep[u] + 1) {
 48             w = flow - used;
 49             w = dfs(v, min(w, E[i].c));
 50             E[i].c -= w;  E[i^1].c += w;
 51             if(v) cur[u] = i;
 52             used += w;
 53             if(used == flow) return flow;
 54         }
 55     }
 56     if(!used) dep[u] = -1;
 57     return used;
 58 }
 59 int dinic() {
 60     int ans = 0;
 61     while(bfs()) {
 62         for(int i = 0; i <= T;i++)
 63             cur[i] = head[i];
 64         ans += dfs(S, inf);
 65     }
 66     return ans;
 67 }
 68 void print(int x, int &f) {
 69     if(x <= S) return;
 70     if(f == 1) f = 0;
 71     else printf(" ");
 72     printf("%d", x);
 73 
 74     for(int i = head[x]; ~i; i = E[i].nex) {
 75         if(!E[i].c){
 76             print(E[i].v - n, f);
 77         }
 78     }
 79 }
 80 int main() {
 81     int i, j, u, v;
 82     scanf("%d%d", &n, &m);
 83     memset(head, -1, sizeof(head));
 84     cnt = 0;
 85     S = 0; T = 2*n+1;
 86     vector<int>g[N];
 87     for(i = 0; i <= n; ++i) g[i].clear();
 88     for(i = 0; i < m; ++i) {
 89         scanf("%d%d", &u, &v);
 90         add(u, v+n, 1); add(v+n, u, 0);
 91     }
 92     for(i = 1; i <= n; ++i) add(S,i,1),add(i,S,0);
 93     for(i = 1; i <= n; ++i) add(i+n,T,1),add(T,i+n,0);
 94     
 95     int ans = dinic();
 96     
 97     for(i = head[T]; ~i; i = E[i].nex) {
 98         if(!E[i].c) {
 99             int f = 1;
100             print(E[i].v - n, f);
101             puts("");
102         }
103     }
104     printf("%d\n", n-ans);
105     return 0;
106 }
107 
108 /*
109 7 7
110 1 2
111 1 3
112 2 4
113 3 4
114 4 5
115 4 6
116 5 7
117 */
View Code

猜你喜欢

转载自www.cnblogs.com/GraceSkyer/p/9017019.html