现在的位置: 首页 > 综合 > 正文

poj 1422 Air Raid(最小路径覆盖 + 二分图最大匹配)

2014年04月05日 ⁄ 综合 ⁄ 共 932字 ⁄ 字号 评论关闭

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;
}





抱歉!评论已关闭.