二分图指,具有L,R两个点集合,每个集合内没有连边,集合之间的点有连边。
二分图最大匹配问题是指,找到一个确定边最多。即选择的边最多,且任何两边都没有公共点。若两个集合内的点都被匹配上,成为完美匹配。
这类问题可以用网络流,但是匈牙利算法更加简洁。
这就是一个二分图模型,设左边深蓝色的点为L集,右边粉红色的点为R集合,黑色的边为可连边。
(1):找L1的首可连边,再找L2的首可连边,这两个R集的R1,R2点都是未盖点(称未匹配点为未盖点)。得到这个图:
(2)我们为L集第三点找确定边,我们先找首可连边(即这个点连边的最上面的一条边)L3-R1,我们发现这个点已经匹配,则我们强制将这个匹配给L3。R1的原匹配点L1需要重新匹配,L1的最先可连边且未匹配边的点为L1-R2,我们发现R2已经被L2匹配了,我们强制L1匹配R2。然后我们需要为R2的原可连边找新的匹配点,L2的最先可连边且未匹配边为L2-R3,发现R3为未匹配点,那么L2匹配R3结束。
从上面的图中可以看到,这次我们连边的路径是先从未匹配点开始,以此经过未匹配边,匹配边,未匹配边,匹配边,未匹配边,最后到一个未匹配点。 这就是匈牙利算法的核心
(3)为L4确定边,还是上面黑字的思路进行匹配。
走到5的时候发现,L4-R1已经是匹配边,继续一直走下去会死循环,或者说在代码中,会实现这一步返回false,然后L2换一条边出发。
回溯到L2,选择L2-R4,继续匹配
最终得到一个完美匹配图
模板代码:
int used[maxn],g[maxn][maxn],book[maxn];
int Ln,Rn;
bool find(int x){
for(int i=1;i<=Rn;i++){
if(used[i]==0&&g[x][i]){
used[i]=1;
if(book[i]==0||find(book[i])){
book[i]=x;
return true;
}
}
}
return false;
}
for(int i=1;i<=Ln;i++){
memset(used,0,sizeof used);
if(find(i)==false)
flag=0;
}