您的位置:首页 > 大数据 > 人工智能

zoj 1525 Air Raid 有向无环图的最小路径覆盖(匹配)

2013-11-12 13:32 393 查看
题目大意:先解释有向无环图的路径覆盖,在图中找一些不相交的简单路径,使之覆盖图中所有顶点,且每一顶点只有一条路径与之关联,也就是说,若沿着这些路径中每条路径从起点走到终点,则可以恰好经过图中每一个顶点一次且仅一次。该题是求最小路径覆盖,即使得路径条数最小。

题中的限制在顶点,将图转换为二分图,每个顶点v拆为v*和v**,若在图中存在从u到v的有向边,则在二分图中连接一条从u*到v**的边。则有公式:最小路径覆盖数=节点数n-该二分图匹配数。

现在来证明:在原图中先选择所有顶点,若在二分图中添加一条匹配边<v*,u**>,则v与u被并到了一条路径上,所以路径覆盖数可以减少1,继续添加,直到不存在匹配边为止,因此,二分图上的每条匹配边与原图的路径上的某条有向边对应,相反,对于原图的路径上的每条边,对应到二分图上也组成一个匹配,若不是匹配,则存在某顶点与多条边关联,不符合路径覆盖定义。

#include <stdio.h>
#include <string.h>
#define N 500
int g

,mk
,cx
,cy
;
int ans,n;

int path(int u)
{
int i;
for(i=1;i<=n;i++)
{
if(g[u][i]&&!mk[i])
{
mk[i]=1;
if(cy[i]==-1||path(cy[i]))
{
cx[u]=i;
cy[i]=u;
return 1;
}
}
}
return 0;
}

void solve()
{
int i;
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
for(i=1;i<=n;i++)
if(cx[i]==-1)
{
memset(mk,0,sizeof(mk));
ans+=path(i);
}
}

int main()
{
int i,x,y,t,m;
scanf("%d",&t);
while(t--)
{
ans=0;
scanf("%d",&n);
scanf("%d",&m);
memset(g,0,sizeof(g));
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
g[x][y]=1;
}
solve();
printf("%d\n",n-ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: