您的位置:首页 > 理论基础 > 计算机网络

【网络流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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络流24题