二分图匹配也叫匈牙利算法(似乎是匈牙利人提出的)。二分图的匹配最简单的例子就是——撮合一对对CP,然后使方案达到最优(这里的最优一般是CP对数最多)。说的学术化一点,就是有两列数,然后左列的数和右列的数有连线,而每个点只能和1个点连线,而且是另外一列的,求最优方案有多少条连线。
(个人觉得这里讲的很好^_^:
http://blog.csdn.net/dark_scope/article/details/8880547)
在上面的网页中,很生动的讲述了匈牙利算法的原理——是什么样的一个原理呢?假设有两列数(我不用CP了)a列,b列(假设a列有n个数,b列有m个数,那么他是O(nm)的)。如果a列的前x-1个数都与b列的其中一数匹配好了,当前正在匹配a列的第x个数。那么,如果我们枚举b列每一个与x直接有边相连的节点(假设为y),接下去有2种情况——
- y还没有与a列的任何数匹配过,则把x和y匹配上,匹配对数++;
- y与a列的数已经配好了,尝试一下是否能让y原先匹配的节点z=match[y]与b列的其他节点匹配,如果可以,则将x和y匹配上,匹配对数++;否则x就没得匹配了(真可悲)。
那么我们发现这是一个逐层递归的过程,所以可以通过DFS来实现,DFS返回bool值即上述第2点的让z=match[y]重新匹配是否可能。那么,期间,我们还要用一个数组vis,记录一下当前搜索到的节点(一定是b列的节点)是否遍历过,如果遍历过则不能与其匹配(可以这样理解,这个b列的数在这之前就被一个a列的数“预约”了,它不能违约),防止死循环出现。而在给a列的每一个数匹配的最开始,vis数组是要清0的,而match数组不需要。为什么?因为match是已经配好的连接方案,而vis数组则只是临时的一个数组,只是判断当前这个节点在当前情况(即a列新增一个节点)下是否遍历过。其实匈牙利算法很好理解(最好的理解方法应该是CP),其中的重点部分是建边而不是DFS,还要看的出来(很多题目就是深藏不露,看不出来,即使看出来,边也许也很多限制,很难建)。