POJ 3041 Asteroids 匈牙利算法 最小点覆盖

Asteroids

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 8785 Accepted: 4702

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

 

 题意:在一个N*N的矩阵中 有K个障碍物,你有一个武器 每次使用 可以清除某行 或 某列 的障碍物,但是这种武器非常昂贵,所以你要尽可能少的使用;输出 最少使用多少次武器 可以清除所有的障碍物;

 

思路:将 X与 Y 视为 顶点,将障碍物视为u连接 Xi,Yi的边。则可以得到一个二分图G( Vx,Vy,E);

问题所求 就是该图的 最小点覆盖, 根据Koing定理:一个二分图G中的最大匹配数m 等于 G的最小点覆盖数C,即m=C;

使用 匈牙利算法 求得m。

 

#include <iostream>
using namespace std;
const int N = 510; //定义 顶点最大个数
bool map[N][N],used[N]; //保存 顶点 边关系
int link[N]; //记录 与Xi关联的Yi元素 line[Yj] = Xi,-1表示未关联 
int n,k; //定义 顶点数 与边数
bool DFS(int t) //检验顶点t 是否可以增广
{
	for(int i=1; i<=n; i++) //Y中所有顶点 i
	{
		if(!used[i] && map[t][i]) //如果顶点i 未被使用,并且t与i有边相连
		{
			used[i] = true; //将顶点i标记
			if(link[i]==-1 || DFS(link[i]))//如果顶点i 没有 被标记的边连接到 t,
				                           //或者 i与X中的顶点link[i]构成的边被标记 但X的顶点link[i]可以增广
			{
				link[i] = t;//修改边的标记方式,使顶点t与i构成的边关系被标记;
				return true;//可以增广
			}
		}
	}
	return false;
}
int main()
{
	int i,x,y,ans=0;
	memset(link, -1, sizeof(link));//初始化
	memset(map, false, sizeof(map));
	scanf("%d %d", &n, &k);
	for(i=0; i<k; i++)
	{
		scanf("%d %d", &x, &y);
		map[x][y] = true;
	}
	for(i=1; i<=n; i++)//选择一个顶点Xi
	{
		memset(used, false, sizeof(used));//将 所有X顶点设为未标志
		if(DFS(i)) ans++;//如果Xi可以增广,匹配数加1
	}
	printf("%d\n", ans);
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值