Asteroids(POJ--3041 【二分图的最小顶点集 = 二分图的最大匹配】

本文介绍了一个有趣的算法问题,即如何利用一种特殊武器清除太空中的小行星,以帮助太空飞船安全通过。武器可以清除整个行或列的小行星,目标是最少使用次数达到目的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.

题意:Bessie想驾驶这他的太空飞船穿过一个危险的行星地带,这个行星带里有k个小行星,这k个小行星分布在一个n*n的方格里。Bessie有个威力超大的武器,这个武器发射一次就可以消灭一行或一列的所有行星,由于武器发射一次的代价会很大,求要消灭所有的行星最少需要发射几次。先输入n和k分别代表方格的规格和行星的个数,接下来k行分别代表每个行星的坐标。

思路:根据题目要求建立二分图,即将x坐标当成一个集合,将y坐标当成一个集合,求最大匹配数。


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


#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define Size 510
#define INF 0x3f3f3f3f
using namespace std;
int mmap[Size][Size],match[Size],chk[Size],n;  //match[i]存储了匹配的方案,初始值为-1,表示第i点还未匹配,chk[i]记录点是否被扫描过
int dfs(int p)
{
    int t;
    for(int i=1; i<=n; i++)
    {
        if(mmap[p][i]&&!chk[i]) //找p的一个对应点且该点没有检查过(检查指尝试过更改i的匹配)
        {
            chk[i]=1;                     //设检查标志
            t=match[i];                 //取出i的原匹配t
            match[i]=p;                //保证新的匹配方案
            if(t==-1||dfs(t))         //若t点是一个初始值,表示i点原来没有匹配,则增广成功返回或者t点能重新找到一个新的匹配点
                return 1;
            match[i]=t;                 //若不成功,则恢复i点原匹配方案,重新找点来增广
        }
    }
    return 0;                             //p点不能增广进去
}
int main()
{
    //freopen("lalala.text","r",stdin);
    int m,x,y;
    while(~scanf("%d %d",&n,&m))
    {
        memset(mmap,0,sizeof(mmap));
        memset(match,-1,sizeof(match));
        for(int i=0; i<m; i++)
        {
            scanf("%d %d",&x,&y);
            mmap[x][y]=1;
        }
        int cnt=0;
        for(int i=1; i<=n; i++)                   //对n个点依次进行增广
        {
            memset(chk,0,sizeof(chk));    //一次增广中对chk初始化
            cnt+=dfs(i);                               //增广成功,表示i点找到了一个匹配,多了一条匹配边
        }
        printf("%d\n",cnt);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值