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

poj 3020 Antenna Placement(最小路径覆盖 + 匈牙利算法)

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

http://poj.org/problem?id=3020

题意:

给一个n*m的地图,只包含 ' * '和' o'。' * '表示城市,'o'表示空地。现在,要给地图上的城市覆盖天线,若放置一个基站,同时它可以覆盖与它相邻的四个城市(上下左右)。问最后至少需要多少个基站使得所有的城市都能覆盖天线。


思路:看了XY的解题思路,我突然发现这题和poj 1422神似。。其实,建图是一个很关键的问题。开始我就一直纠结于建图。

在poj1422中,给你一个有向无环图和一些边的连接情况,让你选取最少的顶点,从这些顶点出发能够遍历到所有点,这是一个最小路径覆盖的问题。其实,在这里也类似。城市数目设为n,我们可以在基站(任选一个城市)和与它相邻的四个城市(若有城市)建边,那么最后会形成一个有向图。

选取基站覆盖所有的城市就相当于在这个有向图中选取最少的路径来覆盖所有的城市,其实是最小路径覆盖问题。对于有向图,它的最小路径覆盖与它的最大匹配有关。求最大匹配,同poj1422一样,先将每个城市拆点V*,V**,若原来城市i与城市j之间有一条有向边,那么在Vi*与Vj**之间建一条无向边。建图完成后对该图求最大匹配。那么答案就是总的*数 - 最大匹配/2。


#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;
const int maxn = 450;

int n,m;
int cnt;// *的总数减1,因为cnt从0开始的
bool map[maxn][maxn];//建图。(关键)
int tmp[45][15];//原图
char str[15];
int match[maxn];
int chk[maxn];

int dfs(int p)
{
	for(int i = 0; i <= cnt; i++)
	{
		if(map[p][i] && !chk[i])
		{
			chk[i] = 1;
			if(match[i] == -1 || dfs(match[i]))
			{
				match[i] = p;
				return 1;
			}
		}
	}
	return 0;
}

int main()
{
	int test;
	scanf("%d",&test);
	while(test--)
	{
		scanf("%d %d",&n,&m);
		memset(tmp,-1,sizeof(tmp));
		memset(map,false,sizeof(map));

		cnt = -1;
		for(int i = 0; i < n; i++)
		{
			scanf("%s",str);
			for(int j = 0; j < m; j++)
			{
				if(str[j] == '*')
				{
					cnt += 1;//个数加1
					tmp[i][j] = cnt;//给每个 * 编号
				}
			}
		}

		for(int i = 0; i < n; i++)
		{
			for(int j = 0; j < m; j++)
			{
				if(tmp[i][j] >= 0)	//拆点建图
				{
					if(i > 0 && tmp[i-1][j] >= 0)
						map[ tmp[i][j] ][ tmp[i-1][j] ] = true;
					
					if(i < n-1 && tmp[i+1][j] >= 0)
						map[ tmp[i][j] ][ tmp[i+1][j] ] = true;
					
					if(j > 0 && tmp[i][j-1] >= 0)					
						map[ tmp[i][j] ][ tmp[i][j-1] ] = true;
					
					if(j < m-1 && tmp[i][j+1] >= 0)					
						map[ tmp[i][j] ][ tmp[i][j+1] ] = true;
				}
			}
		}

		memset(match,-1,sizeof(match));
		int ans = 0;

		for(int i = 0; i <= cnt; i++)
		{
			memset(chk,0,sizeof(chk));
			if(dfs(i))
				ans+=1;
		}
		printf("%d\n",cnt+1-ans/2);
	}
	return 0;
}

抱歉!评论已关闭.