zoukankan      html  css  js  c++  java
  • poj1719

    二分图匹配

    题意:给定一个r*c的棋盘,其中每列有2个白色格子,其余为黑色。要求选出c个白色格子,且每列一个,且每行至少一个。问能否实现,给出方案。

    分析:如果r>c则必定无法满足,因为即使每列一个,均位于不同行,还是会有某些行没有被选中的格子。对于其余情况,先进行简单的二分图匹配(每行作为1点构成第一点集,每列作为1点构成第二点集,每个白色格子作为连接其行列点的边),如果每行都能匹配上则首先可以保证每行都有选中的格子,当然此时可能有一些列还有没有被选中的格子,只要在该列里随便选1个白的就行了,不会影响结果。

    View Code
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    using namespace std;

    #define maxn 1005

    int uN, vN;
    bool g[maxn][maxn];
    int xM[maxn], yM[maxn];
    bool chk[maxn];

    bool SearchPath(int u)
    {
    int v;
    for (v = 0; v < vN; v++)
    if (g[u][v] && !chk[v])
    {
    chk[v] = true;
    if (yM[v] == -1 || SearchPath(yM[v]))
    {
    yM[v] = u;
    xM[u] = v;
    return true;
    }
    }
    return false;
    }

    int MaxMatch()
    {
    int u, ret = 0;
    memset(xM, -1, sizeof(xM));
    memset(yM, -1, sizeof(yM));
    for (u = 0; u < uN; u++)
    {
    if (xM[u] == -1)
    memset(chk, false, sizeof(chk));
    if (SearchPath(u))
    ret++;
    }
    return ret;
    }

    void input()
    {
    scanf("%d%d", &uN, &vN);
    memset(g, 0, sizeof(g));
    for (int i = 0; i < vN; i++)
    {
    int a, b;
    scanf("%d%d", &a, &b);
    a--;
    b--;
    g[a][i] = g[b][i] = true;
    }
    }

    void work()
    {
    if (uN > vN)
    {
    printf("NO\n");
    return;
    }
    int ans = MaxMatch();
    if (ans != uN)
    {
    printf("NO\n");
    return;
    }
    if (yM[0] != -1)
    printf("%d", yM[0] + 1);
    else
    {
    int j = 0;
    while (!g[j][0])
    j++;
    printf("%d", j + 1);
    }
    for (int i = 1; i < vN; i++)
    {
    if (yM[i] != -1)
    {
    printf(" %d", yM[i] + 1);
    continue;
    }
    int j = 0;
    while (!g[j][i])
    j++;
    printf(" %d", j + 1);
    }
    }

    int main()
    {
    //freopen("t.txt", "r", stdin);
    int t;
    scanf("%d", &t);
    while (t--)
    {
    input();
    work();
    putchar('\n');
    }
    return 0;
    }
  • 相关阅读:
    Timer类的常见使用方法
    转:HTTP协议简介
    DS-5新加交叉编译工具
    C++的引用
    C++构造函数的几种使用方法
    Eclipse 快捷键
    eclipse Outline里图标的含义
    Linux 内存映射函数 mmap()函数详解
    Sockit 硬件接口编程——点亮一个LED
    更新Preloader与uboot
  • 原文地址:https://www.cnblogs.com/rainydays/p/2195942.html
Copyright © 2011-2022 走看看