POJ 3041 Asteroids题解

POJ 3041 Asteroids题解

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).

题意:给出一个N*N的矩阵,有的位置有行星。已知一枪可以击溃一行或一列上的所有行星。问最少多少枪可以击溃 所有的行星。

思路:由于武器发出的光束只能摧毁一行或者一列小行星,所以可以将问题转换成图。其中,光束作为图的顶点,小行星作为连接对应光束的边,光束的攻击方案就对应一个顶点集合G,题目中满足要求的摧毁方案就可以转换成图中每条边都至少有一个属于S的端点。问题就可以转换成求图的最小顶点覆盖问题。而在二分图中,最小点覆盖数=最大匹配数,所以本题可以用最小二分图的最大匹配算法求解——匈牙利算法。

PS.推荐一篇关于讲解匈牙利算法的很有趣的文章——趣写算法系列之--匈牙利算法

代码:

#include 
#include 
using namespace std;
const int MAXN = 510;
int N, K;
int v1, v2; //二分图顶点集,分别表示行和列中的元素个数
bool map[MAXN][MAXN];  //存储小行星的位置
bool visit[MAXN];  //记录v2中的每个点是否被搜索过
int link[MAXN];  //记录v2中的点y在v1中所匹配的点x的编号
int result;  //最大匹配数
bool dfs(int x)  //搜索
{
	for(int y=1;y<=v2;y++) //扫描v2中的每个元素
		if (map[x][y] && !visit[y])  //地图中存在小行星且未被匹配
		{
			visit[y] = true;
			if (link[y] == 0 || dfs(link[y]))
			{
				link[y] = x;
				return true;
			}
		}
	return false;
}
void hungary()  //匈牙利算法
{
	for (int x = 1; x <= v1; x++)
	{
		memset(visit, false, sizeof(visit)); //清空cisit中的元素
		if (dfs(x))  //从v1中的节点x开始寻找增广路径p 
			result++;
	}
}
int main()
{
	while (cin>>N>>K)
	{
		v1 = v2 = N;
		int x, y;
		memset(map, 0, sizeof(map));
		while (K--)
		{
			cin >> x >> y;
			map[x][y] = true;
		}
		hungary();
		cout << result;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39924920/article/details/78462120