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

Description

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

Input

    第1行:两个整数N和K,用一个空格隔开.

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

Output

    一个整数表示贝茜需要的最少射击次数,可以消除所有的小行星

题解:

二分图,两列点分别表示行、列。

对于一个点(x,y) 由 x向y连边。

最小覆盖即是答案。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
//by zrt
//problem:
using namespace std;
typedef long long ll;
const double eps=1e-9;
int H[505],P[10005],X[10005],tot;
int n,k;
inline void add(int x,int y){
    P[++tot]=y;X[tot]=H[x];H[x]=tot;
}
bool cover[505];
int link[505];
int ans;
bool find(int k){
    for(int i=H[k];i;i=X[i]){
        if(!cover[P[i]]){
            int q=link[P[i]];
            link[P[i]]=k;
            cover[P[i]]=1;
            if(q==-1){
                ans++;return true;
            }
            if(find(q)) return true;
            link[P[i]]=q;
        }
    }
    return false;
}
int main(){
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    scanf("%d%d",&n,&k);
    for(int i=0,x,y;i<k;i++){
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    memset(link,-1,sizeof link);
    for(int i=1;i<=n;i++){
        memset(cover,0,sizeof cover);
        find(i);
    }
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/zrts/p/bzoj1741.html