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

什么是二分图最大匹配?

对于二分图G的一个子图M,若M为其边数最多的子图,
则称M为G的最大匹配。

举个栗子:

有一批男女,异性之间互有好感,不存在同性恋,一个人可以同时对多名异性有好感。这样我们就可以根据暗恋关系建图,互相有好感则连一条边。这样得到的就是一个二分图。因为我们可以将其分为男性和女性两个互不相交的子集,且两个子集之间有连线,同一个子集之中没有连线。 然后让我们当一回月老,进行牵线。规定不准脚踏多只船,一个人只能和一名异性牵手成功。而且要根据好感决定,互相没有好感的不能牵手。那么怎样选择能使牵手的情侣数最多呢?这就是一个求最大匹配的问题了。

如何实现二分图最大匹配?

嗯,就用常见的匈牙利算法吧,看个图:

左边的是男生,右边的是女生,如果男生\(x\)与女生\(y\)有边,代表女生\(y\)可以匹配给男生\(x\)(喜不喜欢的问题啦)。我们要把女生匹配给男生,当然匹配的越多越好,这就是二分图最大匹配了(<_>)。

上的信息用邻接矩阵存储哦!我们还需要记录每个女生匹配给了谁。

首先我们把\(1\)号男生和\(1\)号女生来结合(走一步算一步啦)。

然后轮到\(2\)号男生了,他先找\(1\)号女生,但是\(1\)号女生匹配给了\(1\)号男生,于是我们把他与\(2\)号女生结合了\(QAQ\)

然后再看\(3\)号男生,啊,\(3\)号男生只喜欢\(1\)号女生,然而\(1\)号女生已经匹配给了\(1\)号男生,这可如何是好?

没关系,我们让\(1\)男生看看能不能找到别的女生,很显然,\(1\)号男生找到了\(3\)号女生,于是他们就结合了,于是\(1\)号男生告诉\(3\)号男生:我找到另外一个女生辣!

于是\(3\)号男生和\(1\)号女生结合了,\(1\)号男生又找到了\(3\)号女生。

然后来到了最后一位男生,\(4\)号男生,然鹅他也只喜欢\(1\)号女生,于是他硬着头皮找到了\(3\)号男生,\(3\)男生不干了,我就有这一个妹纸,可不行呀,于是我们可爱的4号男生就放弃了。

我们没人爱的\(4\)号女生还是真的可怜!

那么这个图的最大匹配是\(3\),其中,\(1\)号男生直接匹配了\(1\)号女生是因为\(1\)号女生没有人,而后来\(1\)号女生匹配给了\(3\)号男生是尝试把\(1\)号男生匹配给别人,这是一个递归的过程,结果返回匹配成功,当然了,第二次\(4\)号请\(3\)号重新匹配返回的是失败。

洛谷 P3386 【模板】二分图匹配

Code

/*
P3386 【模板】二分图匹配
算法:匈牙利算法 
时间:2018 8 22
by @liyifeng 
*/
#include<bits/stdc++.h>
using namespace std;
int n,m,e;
int edge[1001][1001],vis[1001],match[1001],ans=0;
//edge:邻接矩阵存图  vis:标记 match:匹配情况 ans:最大匹配 
int Hungary(int u)
{
    for(int i=1;i<=m;i++)//尝试匹配对应的每一个点 
        if(edge[u][i]&&!vis[i])
        //如果可以匹配并且没被匹配(A与B有边,且B不与别的点有边) 
        {
            vis[i]=1;
            if(!match[i]||Hungary(match[i])) //算法主体 
            //如果每有被匹配就直接匹配
            //或者尝试把这个点被匹配的点匹配其他的点成功了 
            //其实这个尝试就是一个递归,联锁的反应,会在递归中匹配路上的点
            {
                
                match[i]=u;//被匹配了 
                return 1;
            }
        }
    return 0; //匹配失败 
}

int main()
{
    cin>>n>>m>>e;//读入 
    for(int i=1;i<=e;i++)
    {
        int x,y; cin>>x>>y;
        edge[x][y]=1; //二分图使用邻接矩阵来存图 
    }
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis));//每次千万别忘了清0标记! 
        if(Hungary(i)) ans++;//匹配成功,ans++ 
    }
    cout<<ans<<endl;//输出结果 
    return 0;
}

声明

部分内容来自博客:Link,同时参考百度百科

猜你喜欢

转载自www.cnblogs.com/lyfoi/p/9614778.html
今日推荐