【PowerOJ1738】最小路径覆盖

给定有向图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.txt提供输入数据。文件第1 行有2个正整数n和m。n是给定有向无环图 G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数i和j,表示一条有向边(i,j)。
程序运行结束时,将最小路径覆盖输出到文件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 }

 

posted @ 2017-05-17 13:35  PIPIBoss  阅读(171)  评论(0编辑  收藏  举报