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

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

2014-01-23 13:24 190 查看
【问题分析】

有向无环图最小路径覆盖,可以转化成二分图最大匹配问题,从而用最大流解决。

【建模方法】
构造二分图,把原图每个顶点i拆分成二分图X,Y集合中的两个顶点Xi和Yi。对于原图中存在的每条边(i,j),在二分图中连接边(Xi,Yj)。然后把二分图最大匹配模型转化为网络流模型,求网络最大流。

最小路径覆盖的条数,就是原图顶点数,减去二分图最大匹配数。沿着匹配边查找,就是一个路径上的点,输出所有路径即可。

【建模分析】

对于一个路径覆盖,有如下性质:

1、每个顶点属于且只属于一个路径。

2、路径上除终点外,从每个顶点出发只有一条边指向路径上的另一顶点。

所以我们可以把每个顶点理解成两个顶点,一个是出发,一个是目标,建立二分图模型。该二分图的任何一个匹配方案,都对应了一个路径覆盖方案。如果匹配数为0,那么显然路径数=顶点数。每增加一条匹配边,那么路径覆盖数就减少一个,所以路径数=顶点数 - 匹配数。要想使路径数最少,则应最大化匹配数,所以要求二分图的最大匹配。

注意,此建模方法求最小路径覆盖仅适用于有向无环图,如果有环或是无向图,那么有可能求出的一些环覆盖,而不是路径覆盖。

方案很多,这里不输出方案,仅是求出最大流:#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#define push(x) push_back(x)
#define MaxN 120
using namespace std;
const int INF=~0U>>2;
int head[MaxN],h[MaxN],v[MaxN];
int n,m,tot,s,t;
struct edge
{
int v,cap,next;
edge(int x,int y,int c):v(y),cap(c),next(head[x])
{
head[x]=tot++;
}
};
vector<edge> a;
inline void AddEdge(int x,int y,int c)
{
a.push(edge(x,y,c));
a.push(edge(y,x,0));
}
int sap(int x,int lim)
{
if(x==t) return lim;
int sum=0,y,flow;
for(int i=head[x];i!=-1;i=a[i].next)
{
y=a[i].v;
if(a[i].cap>0&&h[y]+1==h[x])
{
flow=sap(y,min(a[i].cap,lim-sum));
a[i].cap-=flow;
a[i^1].cap+=flow;
sum+=flow;
if(sum==lim) return sum;
}
}
if(h[s]<=t||!sum)
{
if(!--v[h[x]]) h[s]=t+1;
v[++h[x]]++;
}
return sum;
}
inline int mf()
{
int ans=0;
v[0]=t+1;
while(h[s]<=t)
ans+=sap(s,INF);
return ans;
}
inline void init()
{
int x,y;
memset(head,-1,sizeof(head));
cin>>n>>m;
t=2*n+1;
while(m--)
scanf("%d%d",&x,&y),
AddEdge(x,y+n,1);
for(int i=1;i<=n;i++)
AddEdge(s,i,1),
AddEdge(n+i,t,1);
}
inline void work()
{
int ans=n-mf();
cout<<ans<<endl;
}
int main()
{
init();
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: