http://poj.org/problem?id=1422
题意:在一个有向无环图中,从一些顶点出发,能遍历到图上所有点,要求初始选择的顶点数最少且顶点不重复遍历。
思路:
如果从某个顶点开始遍历的过程看成是路径的选择,那么问题就转化为在有向无环图中找最少的不想交的简单路径,这些路径覆盖图中的所有顶点。可见是关于最小路径覆盖的问题。
在有向无环图中,最小路径覆盖数 = 节点数 — 其对应二分图的最大匹配数。
最小路径覆盖它要求原图必须是有向无环图。然后根据原图构造二分图,方法为:将原图中的每个顶点vi一分为二,vi* 和vi**,相应的,如果原图中存在一条从vi到vj的有向边,那么就在顶点 vi* 和 vj** 之间连一条无向边,这就构造出一个路径覆盖问题所对应的二分图,在该二分图的基础上求其最大匹配数。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn = 130;
int n,m;
bool map[maxn][maxn];
int match[maxn];
int chk[maxn];
bool dfs(int p)
{
for(int i = 1; i <= n; i++)
{
if(map[p][i] && !chk[i])
{
chk[i] = 1;
if(match[i] == -1 || dfs(match[i]))
{
match[i] = p;
return true;
}
}
}
return false;
}
int main()
{
int test;
int x,y;
scanf("%d",&test);
while(test--)
{
memset(map,false,sizeof(map));
scanf("%d %d",&n,&m);
for(int i = 0; i < m; i++)
{
scanf("%d %d",&x,&y);
map[x][y] = true; //构造二分图
}
memset(match,-1,sizeof(match));
int res = 0;
for(int i = 1; i <= n; i++)
{
memset(chk,0,sizeof(chk));
if(dfs(i)) res += 1;
}
printf("%d\n",n-res);
}
return 0;
}