DAG图(无回路有向图)的最小路径覆盖问题
= 最大匹配+(n-2*最大匹配)
(最大匹配*2为所有可连的点
n-2*最大匹配可求出所有独立点 再加上最大匹配即为最小所需路径)
以下引用博客:http://blog.csdn.net/whosemario/article/details/8513836
定义:
一个有向无环图,要求用尽量少的不相交的简单路径覆盖所有的节点。
构图:
建立一个二分图,把原图中的所有节点分成两份(X集合为i,Y集合为i‘),如果原来图中有i->j的有向边,则在二分图中建立i->j‘的有向边。最终|最小路径覆盖|=|V|-|M|
证明:
上图中,对应左边的DAG构造了右边的二分图,可以找到二分图的一个最大匹配M:1->3’
3->4’,那么M重的这两条匹配边怎样对应DAG中的路径的边呢?
使二分图的一条边对应于DAG中的一条有向边:1->3’对应于左图的1->3,这样DAG中的1就有一个后继结点(3回事1的唯一后继结点,因为二分图中的一个顶点之多关联一条边!),所以1不会成为DAG中的一条路径中的结尾顶点,同样,3->4’对应于左图的3->4,3也不会成为结尾顶点,那么原图中总共有4个顶点,减去2个有后继的顶点,还有两个顶点,即DAG路径的结尾顶点,每个即为顶点对应一个路径。二分图中寻找最大匹配M,就是找到了对应DAG中的非路径结尾顶点的最大数目,那么DAG中|V|-|M|就是DAG中结尾顶点的最小数目,即DAG的最小路径数目。
代码如下:
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
int n;
bool vis[121],mp[121][121];
int link[121];
bool can(int p)
{
int i;
for(i = 1; i <= n; ++i)
{
if(!vis[i] && mp[p][i])
{
vis[i] = true;
if(link[i] == -1 || can(link[i]))
{
link[i] = p;
return 1;
}
vis[i] = false;
}
}
return 0;
}
int main()
{
int t,m,a,b,cnt;
scanf("%d",&t);
while(t--)
{
memset(mp,false,sizeof(mp));
scanf("%d %d",&n,&m);
while(m--)
{
scanf("%d %d",&a,&b);
mp[a][b] = true;
}
memset(link,-1,sizeof(link));
cnt = 0;
for(int i = 1; i <= n; ++i)
{
memset(vis,0,sizeof(vis));
if(can(i)) cnt++;
}
printf("%d\n",n-cnt);
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-10 07:29:28