什么是二分图最大匹配?
对于二分图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,同时参考百度百科