zoukankan      html  css  js  c++  java
  • POJ 3041 /// 二分图匹配

    题目大意:

    n*n的网格中有k个小行星,每一次消除能消除掉一整行或一整列的小行星

    求摧毁所有的小行星最少需要多少次消除

    将位于 i 行 j 列的行星看做连接 i行点 与 j列点 的边

    这样找到最小顶点覆盖(即所有边的某一端点包含在选出的点中)

    相当于找到最大匹配

    #include <bits/stdc++.h>
    using namespace std;
    const int N=1005;
    const int K=10005;
    int n, k, m[N];
    bool vis[N];
    struct NODE { int to,nt; }e[K<<1];
    int head[N], tot;
    void addE(int u,int v) {
        e[tot].to=v;
        e[tot].nt=head[u];
        head[u]=tot++;
    }
    
    /**二分图最大匹配*/
    bool dfs(int u) {
        vis[u]=1;
        for(int i=head[u];i;i=e[i].nt) {
            int v=e[i].to, d=m[v];
            if(!d || !vis[d]&&dfs(d)) { 
            // v还没匹配 或者 本轮匹配中还没搜过且找到其他匹配
                m[u]=v, m[v]=u;
                return 1;
            }
        }
        return 0;
    }
    int match() {
        int res=0;
        memset(m,0,sizeof(m));
        for(int i=1;i<=n;i++)
            if(!m[i]) { // 还没匹配
                memset(vis,0,sizeof(vis));
                if(dfs(i)) res++; // 搜索是否存在合理的匹配 
            }
        return res; // 最大匹配个数
    }
    /***/
    
    int main()
    {
        while(~scanf("%d%d",&n,&k)) {
            tot=1; memset(head,0,sizeof(head));
            for(int i=0;i<k;i++) {
                int r,c; scanf("%d%d",&r,&c);
                addE(r,c+n);  //行编号为1~n 列编号为n+1~n+n
            } // 只建单向边 是因为只从一端找匹配 反向边没意义
            printf("%d
    ",match());
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    idea搭建Spring Boot+Mybatis及使用教程
    CentOS 6 安装配置JDK+tomcat环境
    关于无线路由器之间的连接
    关于链表的面试问题(判断一个单链表中是否有环)
    华为机试ACM(字符组合问题)
    Activity的启动模式
    Notification状态栏显示信息
    Java注释Override、Deprecated、SuppressWarnings
    Fragment
    Service
  • 原文地址:https://www.cnblogs.com/zquzjx/p/10121365.html
Copyright © 2011-2022 走看看