匈牙利算法(二分图最大匹配)

匈牙利算法。复杂度为O(mn)。

对每个点都找以它为起点的增广路,当找到增广路后,匹配数必定加1。

#include 
#include 

const int N = 105;
const int M = 10005;

struct Vertex
{
    int head;
}V[N];

struct Edge
{
    int v,next;
}E[M];

int top,match[N];

bool used[N];

void Init()
{
    top = 0;
    memset(V,-1,sizeof(V));
}

void Add_Edge(int u,int v)
{
    E[top].v = v;
    E[top].next = V[u].head;
    V[u].head = top++;
}

bool dfs(int u)
{
    for(int i=V[u].head;~i;i=E[i].next)
    {
        int v = E[i].v;
        if(!used[v])
        {
            used[v] = true;
            if(!match[v] || dfs(match[v]))
            {
                match[v] = u;
                return true;
            }
        }
    }
    return false;
}

int maxMatch(int n)
{
    int ans = 0;
    memset(match,0,sizeof(match));
    for(int i=1;i<=n;i++)
    {
        memset(used,false,sizeof(used));
        if(dfs(i))
            ++ans;
    }
    return ans;
}


下面介绍几种应用到二分图匹配的常见问题模型。

为了方便,以下我们都设要选取的点集为 U ,总点集为 V,最大匹配的边集为 M。

1、最小顶点覆盖:在二分图中选取最少的点覆盖所有的边(边被覆盖是指被至少选取一个端点)。

1)|U| <= |M|。只需要去覆盖 M 中每条边即可。如果选完后不能覆盖所有的边,则把那条边加入 M,会使 M 变大,与 M 最大矛盾。

2)|U| >= |M|。由于 M 中任意两条边都无公共点,所以覆盖这些边至少就需要 |M| 个点。

2、最大独立集:在二分图中选取最多的点,使这些点互不相连。

1)|U| <= |V| - |M|。M 中每条边最多只能选取一个点放入 U,即至少有一个点不在 U 里面,从而一共至少 |M| 个点不在 U 里面。

2)|U| >= |V| - |M|。首先,不在 M 中出现的点一定都能放入 U,假如不能放,那么将导致相连的这条边加入 M,同样会使 M 变大,与 M 最大矛盾。

然后,M 中每条边至少选取一个点可以放入 U。如果两个点都不能放,那么肯定会出现一条增广路,使 M 变大,与 M 最大矛盾。

3、最小路径覆盖。

你可能感兴趣的:(◆学习笔记,【图论】)