• 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
  • 相关阅读:
    高中教材记录
    帮我解决逆序问题的网友:@18数院啦啦啦。恶人:16 师大 很菜 刘琳(2196879114) 2:32:49 PM
    丘维声的视频地址,全部课堂
    理工医疗报销电话
    可汗化学和二项式定理的地址
    二次函数问题
    *0000181894BD*---------北大医院条形码
    三月里的小雨
    语文容易读错的字
    mongodb部署
  • 原文地址:https://www.cnblogs.com/zquzjx/p/10121365.html
Copyright © 2020-2023  润新知