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\n",aa+bb-ans);//最小覆蓋邊集數=頂點數-最大匹配數 
	}
}


發佈了40 篇原創文章 · 獲贊 0 · 訪問量 5207
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章