poj3020 建信号塔(匈牙利算法 最小覆盖边集)

Antenna Placement
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 10518 Accepted: 5189

Description

The Global Aerial Research Centre has been allotted the task of building the fifth generation of mobile phone nets in Sweden. The most striking reason why they got the job, is their discovery of a new, highly noise resistant, antenna. It is called 4DAir, and comes in four types. Each type can only transmit and receive signals in a direction aligned with a (slightly skewed) latitudinal and longitudinal grid, because of the interacting electromagnetic field of the earth. The four types correspond to antennas operating in the directions north, west, south, and east, respectively. Below is an example picture of places of interest, depicted by twelve small rings, and nine 4DAir antennas depicted by ellipses covering them. 
 
Obviously, it is desirable to use as few antennas as possible, but still provide coverage for each place of interest. We model the problem as follows: Let A be a rectangular matrix describing the surface of Sweden, where an entry of A either is a point of interest, which must be covered by at least one antenna, or empty space. Antennas can only be positioned at an entry in A. When an antenna is placed at row r and column c, this entry is considered covered, but also one of the neighbouring entries (c+1,r),(c,r+1),(c-1,r), or (c,r-1), is covered depending on the type chosen for this particular antenna. What is the least number of antennas for which there exists a placement in A such that all points of interest are covered? 

Input

On the first row of input is a single positive integer n, specifying the number of scenarios that follow. Each scenario begins with a row containing two positive integers h and w, with 1 <= h <= 40 and 0 < w <= 10. Thereafter is a matrix presented, describing the points of interest in Sweden in the form of h lines, each containing w characters from the set ['*','o']. A '*'-character symbolises a point of interest, whereas a 'o'-character represents open space. 

Output

For each scenario, output the minimum number of antennas necessary to cover all '*'-entries in the scenario's matrix, on a row of its own.

Sample Input

2
7 9
ooo**oooo
**oo*ooo*
o*oo**o**
ooooooooo
*******oo
o*o*oo*oo
*******oo
10 1
*
*
*
o
*
*
*
*
*
*

Sample Output

17
5

题目链接:点击打开链接

题目大意:给你一幅图,若干个点,然后有一种信号塔可以向图片上那样上左下右的覆盖,问你最少要建几个信号塔。

思路:这道题和poj3041有一点点像吧(关于3041可以看我另外一篇博客)。只不过那道题是求最小覆盖点,这道题是求最小覆盖边。那怎么想呢,首先,贪心,构造会很麻烦,而且应该是不能成功的(因为给你的图的边不一样,点不一样)而这道题是要我们用若干个东西覆盖若干个东西对不对,这就想到了匈牙利算法里面的两个覆盖。

先提两个定理:最小覆盖点集数=最大匹配数,最小覆盖边集数=顶点数-最大匹配数

此题我们只用到了后者。什么是最小覆盖边集呢,我们知道二分图是用左右两个点集,加中间的边组成的,最小覆盖边集的意思就是,二分图任意一个顶点,都有一条边处于这个集合中,而这个定理的正确性我不予证明(其实是不会)。

这道题我们仔细思考一下,会发现,任意一个点,只能和周围的四个点公用一个信号塔,再想一下,中间的点和周围的点横纵坐标之和奇偶性是刚好相反的,再想一下!整幅图都只有两种点,那就是横纵左边之和为奇数或者为偶数的点,那二分图的点集就建好了,左边是奇数点,右边是偶数点,易得两边都没有自交边,只能和对方相连,那二分图的边是什么呢,显然就是,如果一个奇数点和偶数点相邻,那就是有一条边(也就是两个点可以共用一个信号塔),这样建完了图后,那怎么做就一目了然了,就是求最少的边将点全部覆盖,也就是求最小覆盖边集了。

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#include<iostream>
#include<algorithm>
#define MAXN 10100
#define INF 0x7fffffff
#define max(a,b) a>b?a:b
#define min(a,b) a>b?b:a
using namespace std;
const int maxn=60;
char mp[maxn][maxn];
int g[1000][1000],used[1000],girl[1000];
struct dian{
	int x,y;
}a[1000],b[1000];//统计奇数点和偶数点 
int aa,bb;
bool find(int x){//匈牙利算法 
	for(int i=1;i<=bb;i++){
		if(g[x][i]&&used[i]==0){
			used[i]=1;
			if(girl[i]==0||find(girl[i])){
				girl[i]=x;
				return true;
			}
		}
	}
	return false;
}
int main(){
	int t;
	cin>>t;
	while(t--){
		memset(g,0,sizeof(g));
		memset(girl,0,sizeof(girl));
		int h,w;
		scanf("%d%d",&h,&w);
		for(int i=0;i<h;i++){
			scanf("%s",mp[i]);
		}
		aa=0,bb=0;
		for(int i=0;i<h;i++){
			for(int j=0;j<w;j++){
				if(mp[i][j]=='*'){//
					if((i+j)&1){//统计奇数点和偶数点 
						a[++aa].x=i;
						a[aa].y=j;
					}else{
						b[++bb].x=i;
						b[bb].y=j;
					}
				}
			}
		}
		for(int i=1;i<=aa;i++){//对于每个奇数点  如果偶数点和他相邻  则存在一条边 
			for(int j=1;j<=bb;j++){
				if(a[i].x==b[j].x){
					if(abs(a[i].y-b[j].y)<=1){
						g[i][j]=1;
					}
				}
				if(a[i].y==b[j].y){
					if(abs(a[i].x-b[j].x)<=1){
						g[i][j]=1;
					}
				}
			}
		}
		int ans=0;
		for(int i=1;i<=aa;i++){
			memset(used,0,sizeof(used));
			if(find(i))ans++;
		}
		printf("%d
",aa+bb-ans);//最小覆盖边集数=顶点数-最大匹配数 
	}
}


原文地址:https://www.cnblogs.com/mountaink/p/9536730.html