POJ3041 Asteroids

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

                                                                                      Asteroids

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 28941   Accepted: 15524

Description

Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape of an N x N grid (1 <= N <= 500). The grid contains K asteroids (1 <= K <= 10,000), which are conveniently located at the lattice points of the grid.

Fortunately, Bessie has a powerful weapon that can vaporize all the asteroids in any given row or column of the grid with a single shot.This weapon is quite expensive, so she wishes to use it sparingly.Given the location of all the asteroids in the field, find the minimum number of shots Bessie needs to fire to eliminate all of the asteroids.

Input

* Line 1: Two integers N and K, separated by a single space.
* Lines 2..K+1: Each line contains two space-separated integers R and C (1 <= R, C <= N) denoting the row and column coordinates of an asteroid, respectively.

Output

* Line 1: The integer representing the minimum number of times Bessie must shoot.

Sample Input

3 4
1 1
1 3
2 2
3 2

Sample Output

2

Hint

INPUT DETAILS:
The following diagram represents the data, where "X" is an asteroid and "." is empty space:
X.X
.X.
.X.

OUTPUT DETAILS:
Bessie may fire across row 1 to destroy the asteroids at (1,1) and (1,3), and then she may fire down column 2 to destroy the asteroids at (2,2) and (3,2).

題意就是座標上有一些點,你每次只能清除一行或一列,問你最少多少次,可以將點全部清完。

感覺這個題很像學最大匹配的時候給的例題,當時是一個棋盤上有很多點,刪去多少點使得每行每列都只有一個點。那個題的解法是x座標爲一個點集X,y座標爲一個點集Y,有一個點(x,y),就在x與y連一條邊。每行每列都只有一個點,即相當於X點集中x只能連一條邊(或Y點集中y只能連一條邊)。就轉換成了最大匹配問題。

至於本題,我們也把座標上的一個點(x,y)當成X點集中x與Y點集中y之間有一條邊。我們需要刪去所有座標上的點,等於覆蓋所有X點集與Y點集之間的邊。每次刪去一行(或一列),就相當於選中X點集(或Y點集)中一個點,同時覆蓋所有與x(或y)相連的邊。就是二分圖的最小點覆蓋問題,就是最少的點覆蓋所有的邊。

二分圖的最小點覆蓋=最大匹配數。

證明不再給出。(因爲我自己也沒有看懂網上的講解)

 

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstring>
using namespace std;
const int N=1010;
int m,n,k;//e邊數,m,n分別爲兩個點集中點的數量
int line[N][N];//map用來存邊 
bool used[N];//在回溯過程中是否已被配對
int ans[N];//最後連接的點
bool found(int x)
{
	for(int i=1;i<=n;i++)
		if(line[x][i]&&!used[i])
		{
			used[i]=1;
			if(!ans[i]||found(ans[i]))
			{
				ans[i]=x;
				return 1;
			}
		}
	return 0;	
} 
int main()
{
	while(~scanf("%d%d",&n,&k))
	{
		int x,y;
		memset(line,0,sizeof(line));
		memset(ans,0,sizeof(ans));
		for(int i=0;i<k;i++)
		{
			scanf("%d%d",&x,&y);
			line[x][y]=1;
		}
		int cnt=0;
		for(int i=1;i<=n;i++)
		{
			memset(used,0,sizeof(used));
			if(found(i))
				cnt++;
		}
		printf("%d\n",cnt);
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章