【网络流24题】最小路径覆盖问题
2016-03-11 19:38
441 查看
Description
给定有向图 G=(V,E)。设 P是 G的一个简单路(顶点不相交)的集合。如果 V中每个顶点恰好在 P的一条路上,则称 P是 G的一个路径覆盖。 P中路径可以从 V的任何一个顶点开始,长度也是任意的,特别地,可以为 0。G的最小路径覆盖是 G的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图 G的最小路径覆盖。
提示:设 V={1,2,…,n},构造网络 G1=(V1,E1)如下:
V1 ={x0, x1,., xn }∪{y0, y1,., yn },
E1 ={(x , x ): i ∈V}∪{( y , y ): i ∈V}∪ {(x , y ):(i. j) ∈ E}
每条边的容量均为 1。求网络 G1的( x0, y0)最大流。
对于给定的给定有向无环图 G,编程找出 G的一个最小路径覆盖。
Input
文件第 1行有 2个正整数 n和 m。n是给定有向无环图 G的顶点数, m是 G的边数。接下来的 m行,每行有 2个正整数 i和 j,表示一条有向边 (i,j)。Output
从第 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
HINT
n<150 m<3000
[b]code[/b]
网络流最大流
将图中的每个点拆成两个,分别放入x集合和y集合。
对于一条边(u,v),从x集合中的u到y集合中的v建一条容量为inf的边。
对于x集合中的每个元素,从原点向其建一条容量为1的边。
对于y集合中的每个元素,从其向汇点建一条容量为1的边。
跑一遍最大流,ans=n-最大流。
如果没有匹配,那么说明需要n条路径,每增加一个匹配,则减少一条所需路径覆盖,求最大匹配,即为求最小路径覆盖。
[b]code[/b]
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 20010 #define inf 0x7fffffff using namespace std; struct ss { int next,to,s; }; ss Edge[N<<1]; int n,m,tot=1,T; int head ; int h ; int qq ,in ; void add(int x,int y,int z) { Edge[++tot].next=head[x]; Edge[tot].to=y; Edge[tot].s=z; head[x]=tot; } void ins(int x,int y,int z) { add(x,y,z),add(y,x,0); } bool bfs() { queue<int>Q; Q.push(0); memset(h,-1,sizeof(h)); h[0]=0; while(!Q.empty()) { int u=Q.front(); Q.pop(); for(int i=head[u];i;i=Edge[i].next) { int to=Edge[i].to,s=Edge[i].s; if(!s||h[to]!=-1)continue; h[to]=h[u]+1; Q.push(to); } } if(h[T]==-1)return false; return true; } int dfs(int u,int f) { if(u==T)return f; int used=0; for(int i=head[u];i;i=Edge[i].next) { int to=Edge[i].to,s=Edge[i].s; if(!s||h[to]!=h[u]+1)continue; int w=f-used; w=dfs(to,min(w,s)); if(w&&u&&to!=T)qq[u]=to-n,in[to-n]++; used+=w; Edge[i].s-=w; Edge[i^1].s+=w; if(used==f)return f; } if(!used)h[u]=-1; return used; } int dinic() { int ans=0; while(bfs()) ans+=dfs(0,inf); return ans; } void getans() { for(int i=1;i<=n;i++) { if(!in[i]) { int x=i; printf("%d",x); while(qq[x]) { printf(" %d",qq[x]); x=qq[x]; } puts(""); } } } int main() { // freopen("tt.in","r",stdin); // freopen("path3.in", "r", stdin); // freopen("path3.out", "w", stdout); cin>>n>>m; T=(n<<1)+1; for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); ins(x,y+n,inf); } for(int i=1;i<=n;i++) { ins(0,i,1); ins(i+n,T,1); } int tmp=dinic(); getans(); cout<<n-tmp<<endl; fclose(stdin); fclose(stdout); return 0; }