• POJ 1498[二分匹配——最小顶点覆盖]


    题目链接:【http://acm.hdu.edu.cn/showproblem.php?pid=1498】

    题意:给出一个大小为n*n(0<n<100)的矩阵,矩阵中放入m种颜色(标号为1-m),然后对于每种颜色有k次操作,每次操作可以选择一行或者一列,然后把这一行或者这一列的这种颜色全部去掉,求每种颜色k次操作以后,不能去掉的颜色是哪几种颜色,从小到大输出。

    最小顶点覆盖要求用最少的点(X或Y中都行),让每条边都至少和其中一个点关联。Knoig定理:二分图的最小顶点覆盖数等于二分图的最大匹配数。

    横坐标映射成X点集合,纵坐标映射成Y点,把每个矩阵中相同颜色点的坐标(x,y)建立一条边x->y,目的是选择最少的点把所有的边(即:矩阵中的点)覆盖。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 150;
    int n, k;
    struct node
    {
        int u, v;
    };
    vector<node>E[55];
    vector<int>Edge[maxn], ans;
    void init()
    {
        for(int i = 1; i <= 52; i++)
            E[i].clear();
        ans.clear();
    }
    int fa[maxn], vis[maxn];
    bool match(int u)
    {
        int l = Edge[u].size();
        for(int i = 0; i < l; i++)
        {
            int v = Edge[u][i];
            if(vis[v]) continue;
            vis[v] = 1;
            if(fa[v] == -1 || match(fa[v]))
            {
                fa[v] = u;
                return true;
            }
        }
        return false;
    }
    int hungry()
    {
        int ret = 0;
        memset(fa, -1, sizeof(fa));
        for(int i = 1; i <= n; i++)
        {
            memset(vis, 0, sizeof(vis));
            if(match(i)) ret++;
        }
        return ret;
    }
    int main ()
    {
        while(scanf("%d%d", &n, &k))
        {
            if(n == 0 && k == 0) break;
            init();
            int t, ma = 0;
            for(int i = 1; i <= n; i++)
                for(int j = 1; j <= n; j++)
                {
                    scanf("%d", &t);
                    E[t].push_back(node{i, j});
                    ma = max(ma, t);
                }
            for(int i = 1; i <= ma; i++)
            {
                for(int j = 1; j <= n; j++)
                    Edge[j].clear();
                int l = E[i].size();
                for(int j = 0; j < l; j++)
                    Edge[E[i][j].u].push_back(E[i][j].v);
                if(hungry() > k) ans.push_back(i);
            }
            int l = ans.size();
            if(!l) printf("-1
    ");
            else
            {
                for(int i = 0; i < l - 1; i++)
                    printf("%d ", ans[i]);
                printf("%d
    ", ans[l - 1]);
            }
        }
        return 0;
    }

     

    想的太多,做的太少。
  • 相关阅读:
    C++ 的继承与虚函数 读书笔记
    C++ 类 、构造、 析构、 重载 、单例模式 学习笔记及练习
    C++ 入门随手笔记及联系
    计算机网络通信、线程、tcp、udp通信及信号量等读书笔记
    进程 信号 通信 消息队列 共享内存 进程间通信 等读书笔记及个人小练习
    C++发展概述、优缺点及应用领域
    剪枝例题大全+题解
    (可行性剪枝,上下界剪枝)「一本通 1.3 例 1」数的划分
    呜呜呜
    「一本通 1.3 例 5」weight]
  • 原文地址:https://www.cnblogs.com/pealicx/p/6696326.html
Copyright © 2020-2023  润新知