zoukankan      html  css  js  c++  java
  • [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;
    }
  • 相关阅读:
    bzoj4183: tree
    bzoj4389: ZYB and Trees
    bzoj3253: 改编
    uoj#274. 【清华集训2016】温暖会指引我们前行
    uoj#272. 【清华集训2016】石家庄的工人阶级队伍比较坚强
    uoj#11. 【UTR #1】ydc的大树
    uoj#29. 【IOI2014】Holiday
    uoj#187. 【UR #13】Ernd
    bzoj5019: [Snoi2017]遗失的答案
    bzoj5017: [Snoi2017]炸弹
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/7902469.html
Copyright © 2011-2022 走看看