【PowerOJ1738】最小路径覆盖
Description
给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个 顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶 点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少 的路径覆盖。 设计一个有效算法求一个有向无环图G 的最小路径覆盖。 提示:设V={1,2,... ,n},构造网络G1=(V1,E1)如下: 每条边的容量均为1。求网络G1的( x0 , y0 )最大流。 编程任务: 对于给定的有向无环图G,编程找出G的一个最小路径覆盖。
Input
由文件input.txt提供输入数据。文件第1 行有2个正整数n和m。n是给定有向无环图 G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数i和j,表示一条有向边(i,j)。
Output
程序运行结束时,将最小路径覆盖输出到文件output.txt 中。从第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
题解:
每一个点拆成i和i+n两个,每一个表示他在边中是前驱还是后继,然后所有的前驱init(S,i,1)所有的后继(i+n,T,1)
每一条边(u,v)改成u的前驱到v的后继有一条(u,v+n,INF)的边
然后答案为n-最大流
然后输出路径,已知路径的开始一定后继没有被访问过,所以i+n到T的边依旧为1,可以找出所有路径的开始节点。
然后就是判断他和哪些边匹配过,不断递归输出.
细节很巧妙,详情看代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 const int N=1005,M=200005,INF=1999999999; 7 int gi(){ 8 int str=0;char ch=getchar(); 9 while(ch>'9' || ch<'0')ch=getchar(); 10 while(ch>='0' && ch<='9')str=str*10+ch-'0',ch=getchar(); 11 return str; 12 } 13 int n,m,num=1,head[N],S=0,T,d[N]; 14 struct Lin{ 15 int next,to,dis; 16 }a[M]; 17 void init(int x,int y,int z){ 18 a[++num].next=head[x]; 19 a[num].to=y; 20 a[num].dis=z; 21 head[x]=num; 22 a[++num].next=head[y]; 23 a[num].to=x; 24 a[num].dis=0; 25 head[y]=num; 26 } 27 int q[N],dep[N]; 28 bool bfs() 29 { 30 memset(dep,0,sizeof(dep)); 31 q[1]=S;dep[S]=1; 32 int x,u,t=0,sum=1; 33 while(t!=sum) 34 { 35 x=q[++t]; 36 for(int i=head[x];i;i=a[i].next){ 37 u=a[i].to; 38 if(dep[u] || a[i].dis<=0)continue; 39 dep[u]=dep[x]+1;q[++sum]=u; 40 } 41 } 42 return dep[T]; 43 } 44 int dfs(int x,int flow) 45 { 46 if(T==x || !flow)return flow; 47 int u,tmp,tot=0; 48 for(int i=head[x];i;i=a[i].next){ 49 u=a[i].to; 50 if(dep[u]!=dep[x]+1 || a[i].dis<=0)continue; 51 tmp=dfs(u,min(a[i].dis,flow)); 52 tot+=tmp;flow-=tmp; 53 a[i].dis-=tmp;a[i^1].dis+=tmp; 54 if(!flow)break; 55 } 56 return tot; 57 } 58 int maxflow() 59 { 60 int tmp,tot=0; 61 while(bfs()){ 62 tmp=dfs(S,INF); 63 while(tmp)tot+=tmp,tmp=dfs(S,INF); 64 } 65 return tot; 66 } 67 void hfs(){ 68 int u; 69 for(int i=head[T];i;i=a[i].next){ 70 if(!a[i].dis)d[a[i].to]=true; 71 } 72 } 73 void Print(int x) 74 { 75 printf("%d ",x); 76 for(int i=head[x];i;i=a[i].next){ 77 if(a[i].to!=S && a[i].dis==INF-1)Print(a[i].to-n); 78 } 79 } 80 int main() 81 { 82 int x,y; 83 n=gi();m=gi(); 84 T=2*n+1; 85 for(int i=1;i<=n;i++)init(S,i,1),init(i+n,T,1); 86 for(int i=1;i<=m;i++){ 87 x=gi();y=gi(); 88 init(x,y+n,INF); 89 } 90 int tp=maxflow(); 91 hfs(); 92 for(int i=1;i<=n;i++){ 93 if(!d[i+n])continue; 94 Print(i); 95 printf("\n"); 96 } 97 printf("%d",n-tp); 98 }