首页 > 代码库 > 最小点覆盖,二分图最大匹配—POJ1274 POJ1469 POJ1469

最小点覆盖,二分图最大匹配—POJ1274 POJ1469 POJ1469

二分图最大匹配常用的匈牙利算法,之前写的很幼稚,虽然也过了,但是平白的比别人多开了两倍的空间。

本来就是在填加边的时候把左边的点和右边的点分开算都加在图里面储存,然后匹配的时候就互相匹配

match[u]=v; match[v]=u; 然后看了模板之后才发现其实完全不用加上,只记录match[v]=u就可以了

三题的代码都是一样的,需要注意的是1469题是要求求最小点覆盖数,最小点覆盖数就等于最大匹配数。

简单说下。

首先,最小点覆盖数肯定不会小于匹配数,因为那样连已经匹配的边都没法覆盖掉,何谈没有算在匹配边里的边呢。

其次,二分图么,可以把已经匹配的点分成两个阵营,匹配边的两侧,这样,没有匹配的点(如果有边相连,没有边相连的话就不需要考虑了)

肯定会跟已经匹配的点有一条边连起来,把这样的匹配点放到左阵营中,并且最小覆盖点全部都选则左阵营的已经匹配的点,那就正好是匹配边数了。

不可能又这样的两个未匹配的点,两个点分别与已经匹配的边的两点都有连线,如果这样的话,那么不如拆掉中间的匹配边,两两相连,就又多了一条匹配边。

综上,点覆盖数可以是最大匹配数,但不能小于最大匹配数,所以最小点覆盖数就是最大匹配数。

 

//POJ 1274
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
using namespace std;
const int N = 500 + 5;
const int E = 1e5 + 5;
vector<int> G[N];
int n,m;

int match[N],vis[N];

void init()
{
    for(int i = 0; i < N; i++)
        G[i].clear();
    memset(match, -1, sizeof(match));
}

int dfs(int u)
{
    for(int i = 0; i < G[u].size(); i++)
    {
        int v = G[u][i];
        if(vis[v]) continue;
        vis[v] = 1;
        if(match[v] == -1 || dfs(match[v]))
        {
            match[v] = u;
            return 1;
        }
    }
    return 0;
}

int main()
{
    int num,tmp;
    while(scanf("%d%d", &n, &m) == 2)
    {
        init();
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &num);
            for(int j = 0; j < num; j++)
            {
                scanf("%d", &tmp);
                G[i].push_back(tmp);
            }
        }
        int ans = 0;
        for(int i = 1; i <= n + m; i++)
        {
            memset(vis, 0, sizeof(vis));
            ans += dfs(i);
        }
        printf("%d\n", ans);
    }
    return 0;
}

 

最小点覆盖,二分图最大匹配—POJ1274 POJ1469 POJ1469