您的位置:首页 > 其它

POJ 3401 Asteroids 二分图最大匹配 最小点覆盖

2015-11-20 13:22 627 查看
A - Asteroids

Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d
& %I64u
Submit Status

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

题意:

有一位传说级游戏高手,在闲暇时间里玩起了一个小游戏,游戏中,一个n*n的方块形区域里有许多敌人,玩家可以使用炸弹炸掉某一行或者某一列的所有敌人。他是种玩什么游戏都想玩得很优秀的人,所以,他决定,使用尽可能少的炸弹炸掉所有的敌人。

现在给你一个游戏的状态,请你帮助他判断最少需要多少个炸弹才能炸掉所有的敌人吧。

比如说,下图中X表示敌人

X . X 

. X . 

. X . 

则,他只需要炸掉第1行与第2列就能炸掉所有的敌人,所以只需要两颗炸弹就可以了。

输入第一行是一个整数T,表示测试数据的组数(0<T<=400)。

每组测试数据的第一行有两个整数n,K,其中n表示游戏方形区域的大小。(n<=500,K<=10 000)

随后的K行,每行有两个整数i,j表示第i行,第j列有一个敌人(行和列都从1开始编号)。(1<=i,j<=n)输出对于每组测试数据,输出一个整数表示最少需要的炸弹颗数



2

#include <iostream>
#include<cstdio>
#include<string.h>
using namespace std;
/*
这道题将每行x看成是结点x,没列y看成是结点y,而障碍物的坐标xy看成是从x到y的
一条边。建图后问题就变成了,找最少的点,使得这些点与所有的边相邻,即最小
点覆盖,用匈牙利算法解决。
-------------------------------
定理:最小点覆盖数 = 最大匹配数,即求图的最大匹配即可,匈牙利算法
-------------------------------
模板讲解:
*/
#define maxn 1001
int n,k,g[maxn][maxn],vis[maxn],link[maxn],r,c;
bool find(int v)
{
for(int i=1; i<=n; i++)
{
if(g[v][i] && !vis[i])///如果结点i和v相邻并且未被查找过
{
vis[i] = true;///标记结点i为已查找过
if(link[i] == 0 || find(link[i]))///表示i不再前一个匹配M中||i在匹配M中,但是从与i相邻的节点出发可以有增广路
{
link[i] = v;///记录查找成功记录
return true;///返回查找成功
}
}
}
return false;
}
int main()
{
int ans;
while(scanf("%d%d",&n,&k) != EOF)
{
memset(g,0,sizeof(g));
memset(link,0,sizeof(link));
for(int i = 0; i < k; i++)
{
scanf("%d%d",&r,&c);
g[r][c] = 1;
}
ans = 0;
for(int i=1; i<=n; i++)
{
memset(vis,0,sizeof(vis));//清空上次搜索时的标记
if(find(i))//从节点i尝试扩展
ans++;
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: