二分图的匹配:给定一个二分图G,在G中的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数和即为最大匹配数。
匈牙利算法求二分图最大匹配的思想很简单,就是相当于一个一个尝试每一条边,尽可能地增加匹配数,举个例子:

以这个图为例进行讲解匈牙利算法的思想,我们先让左半部的1号节点进行匹配,按照顺序他会和右半部的1号节点进行匹配,同理左半部的2号节点会和右半部的3号节点进行匹配,左半部的3号节点会和右半部的2号节点进行匹配,轮到左半部的4号节点进行匹配时会发现右半部的2号节点已经与左半部的3号节点匹配成功,所以这个时候就要尝试让左半部的3号节点换一个匹配对象,这个时候左半部的3号节点会选择与右半部的4号节点进行匹配,这个时候右半部的2号节点就空出来了,就可以和左半部的4号节点进行匹配了,所以对应的最大匹配数就是4,这也就是一个逐步尝试的过程,其实正好对应着深搜的过程。
因为右半部是一个被匹配的过程,所以我们只需要用一个match[i]记录右半部的i号节点所匹配的左半部的节点编号即可,如果match[i]=0说明右半部的i号节点还没有进行匹配。
思路明白了,代码就比较容易实现,下面给出一道例题:
题目链接:【模板】二分图最大匹配 - 洛谷

输入样例:
- 4 2 7
- 3 1
- 1 2
- 3 2
- 1 1
- 4 2
- 4 1
- 1 1
输出样例:
2
代码:
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<iostream>
- #include<queue>
- #include<cmath>
- using namespace std;
- const int N=1e5+10;
- int h[N],ne[N],e[N],idx;
- int match[N];//match[i]记录与右半部i号节点相匹配的左半部的节点编号
- bool vis[N];//vis[i]标记右半部的i号节点有没有被考虑过
- void add(int x,int y)
- {
- e[idx]=y;
- ne[idx]=h[x];
- h[x]=idx++;
- }
- bool find(int x)
- {
- for(int i=h[x];i!=-1;i=ne[i])
- {
- int j=e[i];
- if(vis[j]) continue;
- vis[j]=true;
- if(match[j]==0||find(match[j]))
- {
- match[j]=x;
- return true;
- }
- }
- return false;
- }
- int main()
- {
- int n1,n2,m;
- cin>>n1>>n2>>m;
- int u,v;
- memset(h,-1,sizeof h);
- for(int i=1;i<=m;i++)
- {
- scanf("%d%d",&u,&v);
- //因为只需要从左半部向右半部进行匹配,所以只需要加单向边
- add(u,v);
- }
- int ans=0;
- for(int i=1;i<=n1;i++)
- {
- //每个右半部的点都只会被尝试一次,所以每次都需要初始化
- memset(vis,false,sizeof vis);
- if(find(i)) ans++;
- }
- cout<<ans;
- return 0;
- }
最后再给大家稍微提一下最小点覆盖问题,这个问题也是可以利用匈牙利算法来解决的。
最小点覆盖问题就是我们想找到最少的一些点,使得二分图中所有的边的两个顶点至少有一个在这些点之中。
这里就不详细介绍了,直接给大家说出个结论就够用了。
一个二分图中的最大匹配数等于这个图中的最小点覆盖数。