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


P1524 - 【网络流24题】最小路径覆盖问题

Description

给定有向图G=(V,E)。设P是G的一个简单路(顶点不相交)的集合。如果V中每个顶点恰好在P的一条路上,则称P是G的一个路径覆盖。P中路径可以从V的任何一个顶点开始,长度也是任意的,特别地,可以为0。G的最小路径覆盖是G的所含路径条数最少的路径覆盖。
设计一个有效算法求一个有向无环图G的最小路径覆盖。

Input

第1行有2个正整数n和m。n是给定有向无环图G的顶点数,m是G的边数。
接下来的m行,每行有2个正整数i 和j,表示一条有向边(i,j)。

Output

第1行开始,每行输出一条(字典序)路径。最后一行是最少路径数。

Sample Input

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

Sample Output

1 4 7 10 11
2 5 8
3 6 9
3

Hint

数据范围:
1<=n<=150,1<=m<=6000
提示:
设V={1,2,... ,n},构造网络G1=(V1,E1)如下:
P
每条边的容量均为1。求网络G1的(x0,y0)最大流。

Source

有向无环图最小路径覆盖,网络最大流
网络流,二分图

 


构建二分图,将一个点一分为二,A部一个,B部一个,A部代表前驱,B部代表后继。
将边连上,从A部到B部,容量为一。
对于每一条路径,只能有一个入度为0的点和一个出度为0的点,所以路径数=出度为0的点。
然后虚拟源点和汇点跑最大流,n-最大流就是答案。
但是还要输出方案。
当最大流求出来后,整个图上不存在增广路。
考虑与汇点相连的那些点,在残余网络中,若汇点与某个点之间的返回流量<=0
则说明这条边的流量为0,即这个点没有作为后继,所以这个点就可以作为路径的起点。
起点找出来后,就可以一直输出与起点相连的边,直到没有边相连,即这个点没有作为前驱,所以这个点为终点。
 

 1 #include<set>
 2 #include<map>
 3 #include<queue>
 4 #include<stack>
 5 #include<ctime>
 6 #include<cmath>
 7 #include<string>
 8 #include<vector>
 9 #include<cstdio>
10 #include<cstdlib>
11 #include<cstring>
12 #include<iostream>
13 #include<algorithm>
14 using namespace std;
15 struct data{
16   int nex,to,w;
17 }e[20000];
18 int head[310],lev[310],edge=0,ans[310],n;
19 void add(int from,int to,int w){
20   e[++edge].nex=head[from];
21   e[edge].to=to;
22   e[edge].w=w;
23   head[from]=edge;
24 }
25 bool bfs(int s,int t){
26   queue<int>q;
27   memset(lev,0,sizeof(lev));
28   q.push(s);lev[s]=1;
29   while(!q.empty()){
30     int u=q.front();
31     q.pop();
32     for(int i=head[u];i;i=e[i].nex)
33       if(e[i].w>0 && !lev[e[i].to]){
34     q.push(e[i].to);
35     lev[e[i].to]=lev[u]+1;
36     if(e[i].to==t) return 1;
37       }
38   }
39   return 0;
40 }
41 int dfs(int s,int t,int k){
42   if(s==t) return k;
43   int tag=0;
44   for(int i=head[s];i;i=e[i].nex)
45     if(e[i].w>0 && lev[e[i].to]==lev[s]+1){
46       int d=dfs(e[i].to,t,min(k-tag,e[i].w));
47       e[i].w-=d;int op;
48       if(i%2) op=1;else op=-1;
49       e[i+op].w+=d;
50       tag+=d;
51       if(tag==k) return tag;
52     }
53   return tag;
54 }
55 int dinic(int s,int t){
56   int flow=0;
57   while(bfs(s,t)) flow+=dfs(s,t,1999999999);
58   return flow;
59 }
60 void out(int x){
61   if(x<=n && x>0) printf("%d ",x);
62   else return;
63   for(int i=head[x];i;i=e[i].nex)
64     if(e[i].w<=0) out(e[i].to-n);
65 }
66 int main()
67 {
68   freopen("!.in","r",stdin);
69   freopen("!.out","w",stdout);
70   int m,x,y;
71   scanf("%d%d",&n,&m);int s=0,t=2*n+1;
72   for(int i=1;i<=m;i++)
73     scanf("%d%d",&x,&y),add(x,y+n,1),add(y+n,x,0);
74   for(int i=1;i<=n;i++)
75     add(s,i,1),add(i,s,0),add(i+n,t,1),add(t,i+n,0);
76   int ans1=n-dinic(s,t);
77   int kl=0;
78   for(int i=head[t];i;i=e[i].nex)
79     if(e[i].w<=0) ans[++kl]=e[i].to-n;
80   sort(ans+1,ans+1+kl);
81   for(int i=1;i<=kl;i++)
82     out(ans[i]),printf("\n");
83   printf("%d",ans1);
84   return 0;
85 }

 
 

posted @ 2017-03-23 08:52  嘘丶  阅读(228)  评论(0编辑  收藏  举报