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)如下:
每条边的容量均为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(" "); 83 printf("%d",ans1); 84 return 0; 85 }