问题描述:
给定有向图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行开始,每行输出一条路径。文件的最后一行是最少路径数。
题解:
最小路径覆盖,建图方法:把所有点分别加入二分图中的x集和y集,如果i节点可以连向j,就让在x集中的i连向一条在y集的j,权值为inf。然后让S连向x集,权值为1。让y集连向T,权值为1。跑网络流,路径的个数就是点的总数减去最大流的值。 证明理解
统计方案也很好理解,正如''证明理解'',里的那样,如果x集里的u流了容量为一的边到y集里的v,则说明v表示的点在DAG中是u表示的点的后继,那么他们两个在同一个路径覆盖上,用并查集把他们联系起来,最后统计一下就成了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 using namespace std; 10 const int inf=1e9; 11 const int maxn=1000,maxm=120000; 12 int N,M,S,T,ANS; 13 struct Edge{ 14 int to,rest,next; 15 }e[150000]; 16 int head[maxn],cnt=1; 17 inline void Addedge(int x,int y,int z){ 18 e[++cnt].to=y; e[cnt].rest=z; e[cnt].next=head[x]; head[x]=cnt; 19 e[++cnt].to=x; e[cnt].rest=0; e[cnt].next=head[y]; head[y]=cnt; 20 } 21 int dis[maxn]; 22 inline bool BFS(){ 23 memset(dis,0,sizeof(dis)); 24 static queue<int> Q; 25 while(!Q.empty()) Q.pop(); 26 Q.push(S); dis[S]=1; 27 while(!Q.empty()){ 28 int x=Q.front(); Q.pop(); 29 for(int i=head[x];i;i=e[i].next){ 30 int y=e[i].to; 31 if(dis[y]==0&&e[i].rest!=0){ 32 dis[y]=dis[x]+1; 33 Q.push(y); 34 } 35 } 36 } 37 if(dis[T]) return true; 38 return false; 39 } 40 inline int DFS(int x,int flow){ 41 if(x==T) return flow; 42 int tmp,now=0; 43 for(int i=head[x];i;i=e[i].next){ 44 int y=e[i].to; 45 if(dis[y]==dis[x]+1&&e[i].rest!=0){ 46 tmp=DFS(y,min(flow-now,e[i].rest)); 47 e[i].rest-=tmp; 48 e[i^1].rest+=tmp; 49 now+=tmp; 50 if(now==flow) return now; 51 } 52 } 53 if(!now) dis[x]=0; 54 return now; 55 } 56 inline void dinic(){ 57 while(BFS()) ANS-=DFS(S,inf); 58 } 59 60 int fa[maxn]; 61 inline int find(int x){ 62 if(x!=fa[x]) fa[x]=find(fa[x]); 63 return fa[x]; 64 } 65 int main(){ 66 //freopen("path3.in","r",stdin); 67 //freopen("path3.out","w",stdout); 68 scanf("%d%d",&N,&M); 69 ANS=N; S=0; T=N*2+1; 70 for(int i=1,u,v;i<=M;i++){ 71 scanf("%d%d",&u,&v); 72 Addedge(u,v+N,inf); 73 } 74 for(int i=1;i<=N;i++){ 75 Addedge(S,i,1); 76 Addedge(i+N,T,1); 77 } 78 dinic(); 79 for(int i=1;i<=N;i++) fa[i]=i; 80 for(int i=1;i<=N;i++){ 81 for(int j=head[i];j;j=e[j].next){ 82 int y=e[j].to; 83 if(e[j].rest==inf-1){ 84 int u=i,v=y-N; 85 int fau=find(u),fav=find(v); 86 if(fau!=fav){ 87 if(fau<fav) fa[fav]=fau; 88 else fa[fau]=fav; 89 } 90 } 91 } 92 } 93 for(int i=1;i<=N;i++){ 94 if(fa[i]==i){ 95 printf("%d ",i); 96 for(int j=1;j<=N;j++){ 97 if(j!=i&&fa[j]==i) printf("%d ",j); 98 } 99 printf("\n"); 100 } 101 } 102 printf("%d\n",ANS); 103 return 0; 104 }