POJ-3041 Asteroids

Posted on 2021-12-01 11:35  Capterlliar  阅读(9)  评论(0编辑  收藏  举报

题意:给定一张n*n的图和k个点,每次可以消灭一行和一列的点,求最少几次可以把所有点消灭完。

解:第一遍看真看不出这是二分图。。。重学了一遍二分图最大匹配,发现这样的题还挺多的。

二分图最大匹配:选出最多的边,使得没有两条边共用一个顶点;

二分图最小点覆盖:选出最少的点,使得每条边都有一个端点被覆盖。

著名定理:二分图最大匹配=二分图最小点覆盖。

然后来看这道题,可以描述为:选取最少的行和列,使得每个点的横纵坐标至少包含一个。

就是求最小点覆盖嘛。

考虑建图,那直接把横纵坐标连起来跑匈牙利算法。

代码:

#include<stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#include <vector>
using namespace std;
#define ll long long
#define maxx 505
#define inf 0x3f
const int mod=1e9+7;
//#define int long long
vector<int> e[maxx];
int n,k;
int vis[maxx]={0},match[maxx]={0};
int dfs(int now){
    for(int i=0;i<e[now].size();i++){
        int to=e[now][i];
        if(!vis[to]){
            vis[to]=1;
            if(!match[to]||dfs(match[to])){
                match[to]=now;
                return 1;
            }
        }
    }
    return 0;
}
signed main() {
    scanf("%d%d", &n, &k);
    for (int i = 0; i < k; i++) {
        int x, y;
        scanf("%d%d", &x, &y);
        e[x].push_back(y);
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        memset(vis, 0, sizeof vis);
        if (dfs(i))
            ans++;
    }
    printf("%d\n", ans);
    return 0;
}
View Code