POJ1466 Girls and Boys

一.原题链接:http://poj.org/problem?id=1466

二.题目大意:一个人可能跟多个人有暧昧,求彼此没有暧昧关系的人最多的集合。

三,思路:其实就是直接给一个图,让你求最大独立点集。但是这是传说中的NP问题。好在只有男的和女的能发生暧昧关系(题目说的)。

建图如下:

1.一个点认为他可能是男的也可能是女的,于是拆为2个点分在2边。

2.如果原来有连线,就2边连线。

然后匈牙利求最大匹配。注意此时求出的匹配的原图的2倍,因为你把每条边都乘以2了。

(有(童鞋)可能会说,我把第一个人先标记为男的或者女的,然后跟他配对的就是另一个性别,我觉得应该也可以,不过我没试过。不过我觉得会比较麻烦,你还要设一个标记数组来标记性别,扫点的时候还要判断它是哪一边的。而且还有个问题,如果出现过以前没配对过的你要把他弄成男的还是女的?)

求得最大匹配之后,有一个结论:

最大匹配 + 最大独立点集  = 顶点数

看到这个结论就懵B了有木有啊。下面来简单说明一下这个结论:

1.概念扫盲:

最大匹配数:最大独立边集,不相邻的边集。

最小覆盖点数:用最小的点覆盖所有的边,也就是说,图中的每条边,都能在最小覆盖点集合里面找到至少一个点,覆盖这条边。

最大独立点集:图中最多的不相邻的点的集合。

2. 结论:

最小覆盖点数 + 最大独立点数 = 顶点数。

这个我会证,

只要证覆盖点数 +独立点数 = 顶点数。

假设u,v相邻且在顶点数-覆盖点集里面,就是u,v是一条边的2个端点,那么说明u,v不在覆盖点集里面,说明u,v决定的边没法被覆盖,矛盾。于是u,v肯定是独立的点,于是顶点数-覆盖点集里面的点都不相邻。

3.结论

最小覆盖点数 = 最大匹配

每个最小覆盖点的点都对应的是一条最大匹配的边。

4.2的结论和3的结论相加,就完了。

四.代码

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <cstdlib>

using namespace std;

const int INF = 0x3f3f3f3f,
          MAX_N = 509;

class maxMatch
{
public:
    bool connected[MAX_N][MAX_N];
    bool visited[MAX_N];
    int xMatch[MAX_N], yMatch[MAX_N],
        xNum, yNum;

    maxMatch()
    {
        memset(connected, 0, sizeof(connected));
        memset(xMatch, -1, sizeof(xMatch));
        memset(yMatch, -1, sizeof(yMatch));
    }

    bool path(int u)
    {
        int v;
        for(v = 0; v < yNum; v++)
        if(connected[u][v] && !visited[v]){
            visited[v] = true;
            if(-1 == yMatch[v] || path(yMatch[v])){
                yMatch[v] = u;
                xMatch[u] = v;
                return true;
            }
        }
        return false;
    }

    int getRes()
    {
        int u, res = 0;
        for(u = 0; u < xNum; u++){
            memset(visited, 0, sizeof(visited));
            if(path(u))
                res++;
        }
        return res;
    }
};

void readG(int num)
{
    maxMatch G;
    G.xNum = G.yNum = num;
    int i, v, cnt;

    for(i = 0; i < num; i++){
        scanf("%d: (%d)", &i, &cnt);
        while(cnt--){
            scanf("%d", &v);
            G.connected[i][v] = true;
        }
    }
    printf("%d\n", num - G.getRes()/2);
}

int main()
{
    //freopen("in.txt", "r", stdin);

    int i, j, num;
    while(~scanf("%d", &num)){
        readG(num);
    }
}



你可能感兴趣的:(POJ1466 Girls and Boys)