[poj3041]Asteroids(二分图的最小顶点覆盖)

题目大意:$N*N$的网格中有$n$颗行星,若每次可以消去一整行或一整列,求最小的攻击次数使得消去所有行星。

解题关键:将光束当做顶点,行星当做连接光束的边建图,题目转化为求该图的最小顶点覆盖,图的最小顶点覆盖是$NP$问题,又因为该图是二分图(水平方向的点和竖直方向的点),而二分图的最大匹配=最小顶点覆盖,即可求解该问题。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
#define maxn 20020
using namespace std;
typedef long long ll;
int n,m;
struct Edge{
    int nxt;
    int to;
    int w;
}e[maxn];
int head[maxn],cnt;
void add_edge(int u,int v){
    e[cnt].to=v;
    e[cnt].nxt=head[u];
    head[u]=cnt++;
}
int pre[maxn];
bool vis[maxn];
bool dfs(int u){
    for(int i=head[u];i!=-1;i=e[i].nxt){
        int v=e[i].to;
        if(!vis[v]){
            vis[v]=true;
            if(pre[v]==-1||dfs(pre[v])){
                pre[v]=u;
                //pre[u]=v;
                return true;
            }
        }
    }
    return false;
}

int hungary(){
    int ans=0;
    memset(pre,-1,sizeof pre);
    for(int i=1;i<=2*n;i++){
        if(pre[i]==-1){
            memset(vis,0,sizeof vis);
            if(dfs(i)) ans++;
        }
    }
    return ans;
}
int a,b,k;

int main(){
    while(scanf("%d%d",&n,&k)!=EOF){
        memset(head, -1, sizeof head);
        cnt=0;
        for(int i=1;i<=k;i++){
            scanf("%d%d",&a,&b);
            add_edge(a,b+n);
        }
        printf("%d",hungary());
    }
    return 0;
}
原文地址:https://www.cnblogs.com/elpsycongroo/p/7902469.html