[网络流24题] 最小路径覆盖问题

问题描述:

  给定有向图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。跑网络流,路径的个数就是点的总数减去最大流的值。

  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=500,maxm=60000;
 12 inline int read(){
 13     int x=0,f=1;char ch=getchar();
 14     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 15     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
 16     return x*f;
 17 }
 18 int N,M,S,T,ANS;
 19 struct Edge{
 20     int to,next,rest;
 21 }e[maxm];
 22 int head[maxn];
 23 int ecnt=1;
 24 inline void addedge(int x,int y,int r){
 25     e[++ecnt].to=y; e[ecnt].rest=r; e[ecnt].next=head[x]; head[x]=ecnt;
 26     e[++ecnt].to=x; e[ecnt].rest=0; e[ecnt].next=head[y]; head[y]=ecnt;
 27 }
 28 int dis[maxn];
 29 
 30 bool BFS(){
 31     memset(dis,0,sizeof(dis));
 32     dis[S]=1;
 33     static queue<int> Q;
 34     while(!Q.empty()) Q.pop();
 35     Q.push(S);
 36     while(!Q.empty()){
 37         int x=Q.front(); Q.pop();
 38         for(int i=head[x];i;i=e[i].next){
 39             int y=e[i].to;
 40             if(e[i].rest&&dis[y]==0){
 41                 dis[y]=dis[x]+1;
 42                 Q.push(y);
 43             }
 44         }
 45     }
 46     if(dis[T]) return true;
 47     return false;
 48 }
 49 
 50 int to[maxn];
 51 bool vis[maxn];
 52 int DFS(int x,int flow){
 53     if(x==T) return flow;
 54     int now=0,tmp;
 55     for(int i=head[x];i;i=e[i].next){
 56         if(e[i].rest&&dis[e[i].to]==dis[x]+1){
 57             tmp=DFS(e[i].to,min(flow-now,e[i].rest));
 58             if(tmp){
 59                 to[x]=e[i].to;
 60                 if(e[i].to-N>0) vis[e[i].to-N]=true; 
 61             }
 62             e[i].rest-=tmp;
 63             e[i^1].rest+=tmp;
 64             now+=tmp;
 65             if(now==flow) return now;
 66         }
 67     }
 68     if(!now) dis[x]=0;
 69     return now;
 70 }
 71 int dinic(){
 72     int ans=0;
 73     while(BFS()){
 74         ans+=DFS(S,1e9);
 75     }
 76     return ans;
 77 }
 78 int main(){
 79     freopen("path3.in","r",stdin);
 80     freopen("path3.out","w",stdout);
 81     N=read(); M=read();
 82     S=0; T=2*N+1;
 83     for(int i=1,u,v;i<=M;i++){
 84         u=read(); v=read();
 85         addedge(u,N+v,inf);
 86     }
 87     for(int i=1;i<=N;i++){
 88         addedge(S,i,1);
 89         addedge(N+i,T,1);
 90     }
 91     ANS=N-dinic();
 92     for(int i=1;i<=N;i++){
 93         if(vis[i]==false){//没有连向i的边,i作为起点 
 94             printf("%d ",i);
 95             int tmp=i;
 96             while(to[tmp]){
 97                 printf("%d ",to[tmp]-N);
 98                 tmp=to[tmp]-N;
 99             }
100             printf("\n");
101         }    
102     }
103     printf("%d\n",ANS);
104     return 0;
105 }

 

 

 

  

 

你可能感兴趣的:([网络流24题] 最小路径覆盖问题)