BZOJ 1741 [Usaco2005 nov]Asteroids 穿越小行星群题解

该博客介绍了如何解决BZOJ 1741竞赛题目,即在N×N网格中,贝茜需要通过最少的射击次数消除所有位于网格点上的K颗小行星。博主提出了利用行连边构造二分图并寻找最大流的方法来确定最少射击次数。样例输入和输出展示了问题的具体实例。

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

我仿佛又开始写水题了…好颓废…花了五分钟A了…


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.
贝茜想驾驶她的飞船穿过危险的小行星群.小行星群是一个NxN的网格(1≤N≤500),在网格内有K个小行星(1≤K≤10000). 幸运地是贝茜有一个很强大的武器,一次可以消除所有在一行或一列中的小行星,这种武器很贵,所以她希望尽量地少用.给出所有的小行星的位置,算出贝茜最少需要多少次射击就能消除所有的小行星.


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.
    第1行:两个整数N和K,用一个空格隔开.
    第2行至K+1行:每一行有两个空格隔开的整数R,C(1≤R,C≤N),分别表示小行星所在的行和列.

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


INPUT DETAILS:

The following diagram represents the data, where “X” is an
asteroid and “.” is empty space:
X.X
.X.
.X.


Sample Output

2


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,会得到这样的二分图

这里写图片描述

观察这张二分图,我们会发现对于行来说,我们的2行3行5行都可以连8,然而8代表的是(8-5)=第3列,那么意思就是说,无论连(2,8),(3,8)或者是(5,8),都只能连一条边,也就是说如果选择第三列,cnt++,而如上所述3个点都会被覆盖。
这样思考,如果二分图里存在一个匹配组合没有被匹配(也就是找到一个点,他的行和列都没有被打的话),一定要匹配他才能消灭它,如果对于(2,8),(3,8)或者是(5,8)的清况,匹配了一次之后剩下的两个都匹配不上了,就说明已经被打了,不能再匹配了(也即这三个点的行或者列已经被打了)
最多的情况下,我们需要覆盖所有列出现的情况,所以我们只需要寻找最大匹配就行了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#define MAXN 10000+50
using namespace std;
int n,m;
bool vis[MAXN];
struct Line{
    int from,to,nxt;
}line[MAXN];
int head[MAXN],tail; 
int girl[MAXN];
void add_line(int from,int to){
    tail++;
    line[tail].from=from;
    line[tail].to=to;
    line[tail].nxt=head[from];
    head[from]=tail;
}
bool find(int u){
    for(register int i=head[u];i;i=line[i].nxt){
        int v=line[i].to;
        if(!vis[v]){
            vis[v]=true;
            if(girl[v]==-1||find(girl[v])){
                girl[v]=u;
                return true;
            }
        }
    }
    return false;
}
int main(){
    scanf("%d%d",&n,&m);
    for(register int i=1;i<=m;i++){
        int from,to;
        scanf("%d%d",&from,&to);
        add_line(from,n+to);
    }
    memset(girl,-1,sizeof(girl));
    int cnt=0;
    for(register int i=1;i<=m;i++){
        memset(vis,false,sizeof(vis));
        if(find(i))cnt++;
    }
    printf("%d\n",cnt);
    return 0;
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值