题目描述
«问题描述:
给定有向图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
思路:
网络流24题之一;
还是那条性质,求最小割;
每条有向边的u,v加边都是u,v+n;
求出最大流,ans=n-最大流;
然后,我们在求最大流的时候把匹配的点和边做标记以输出路径;
来,上代码:
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define INF 0x7ffffff using namespace std; struct EdgeType { int to,next,flow; }; struct EdgeType edge[24005]; int if_z,n,m,cnt=1,head[505],s=0,t=504; int deep[505],next[505],ans; bool if_[505]; char Cget; inline void in(int &now) { now=0,if_z=1,Cget=getchar(); while(Cget>'9'||Cget<'0') { if(Cget=='-') if_z=-1; Cget=getchar(); } while(Cget>='0'&&Cget<='9') { now=now*10+Cget-'0'; Cget=getchar(); } now*=if_z; } inline void edge_add(int u,int v,int w) { edge[++cnt].to=v,edge[cnt].flow=w,edge[cnt].next=head[u],head[u]=cnt; edge[++cnt].to=u,edge[cnt].flow=0,edge[cnt].next=head[v],head[v]=cnt; } bool BFS() { queue<int>que; memset(deep,-1,sizeof(deep)); que.push(s),deep[s]=0; while(!que.empty()) { int pos=que.front(); for(int i=head[pos];i;i=edge[i].next) { if(deep[edge[i].to]<0&&edge[i].flow>0) { deep[edge[i].to]=deep[pos]+1; if(edge[i].to==t) return true; que.push(edge[i].to); } } que.pop(); } return false; } int flowing(int now,int flow) { if(now==t||flow==0) return flow; int oldflow=0; for(int i=head[now];i;i=edge[i].next) { if(deep[edge[i].to]!=deep[now]+1||edge[i].flow==0) continue; int pos=flowing(edge[i].to,min(flow,edge[i].flow)); if(pos>0) { next[now]=edge[i].to; if(edge[i].to>n) if_[edge[i].to-n]=true; } flow-=pos; oldflow+=pos; edge[i].flow-=pos; edge[i^1].flow+=pos; if(flow==0) return oldflow; } return oldflow; } void dinic() { while(BFS()) ans-=flowing(s,INF); } int main() { in(n),in(m);int u,v;ans=n; for(int i=1;i<=m;i++) { in(u),in(v); edge_add(u,v+n,INF); } for(int i=1;i<=n;i++) { edge_add(s,i,1); edge_add(i+n,t,1); } dinic(); for(int i=1;i<=n;i++) { if(if_[i]) continue; int pos=i; printf("%d",pos); while(next[pos]) { if(next[pos]>n) next[pos]-=n; printf(" %d",next[pos]); pos=next[pos]; } printf(" "); } printf("%d ",ans); return 0; }