二分图最大匹配---匈牙利算法(Hungarian Algorithm)

一、相关概念

1、二分图(bipartite graph)

百度百科上的定义:二分图又称作二部图, 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

通俗地说:把一个图的顶点划分为两个不相交集合 U  和 V ,使得每一条边都分别连接U 、 V  中的顶点。如果存在这样的划分,则此图为一个二分图。图 1 是一个二分图。为了清晰,我们以后都把它画成图 2 的形式。

二分图最大匹配---匈牙利算法(Hungarian Algorithm)_第1张图片                 二分图最大匹配---匈牙利算法(Hungarian Algorithm)_第2张图片                  二分图最大匹配---匈牙利算法(Hungarian Algorithm)_第3张图片                 二分图最大匹配---匈牙利算法(Hungarian Algorithm)_第4张图片

2、匹配·(matching)

匹配:在图论中,一个「匹配」(matching)是一个边的集合,其中任意两条边都没有公共顶点。例如,上图中的图 3、图 4 中红色的边就是图 2 的匹配。

3、最大匹配

最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。图 4 是一个最大匹配,它包含 4 条匹配边。

4、完美匹配

完美匹配:如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。图 4 是一个完美匹配。显然,完美匹配一定是最大匹配(完美匹配的任何一个点都已经匹配,添加一条新的匹配边一定会与已有的匹配边冲突)。但并非每个图都存在完美匹配。

举例来说:如下图所示,如果在某一对男孩和女孩之间存在相连的边,就意味着他们彼此喜欢。是否可能让所有男孩和女孩两两配对,使得每对儿都互相喜欢呢?图论中,这就是完美匹配问题。如果换一个说法:最多有多少互相喜欢的男孩/女孩可以配对儿?这就是最大匹配问题。

二分图最大匹配---匈牙利算法(Hungarian Algorithm)_第5张图片

二、匈牙利算法(Hungarian Algorithm)-------求解最大匹配问题

二分图最大匹配---匈牙利算法(Hungarian Algorithm)_第6张图片

交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边...形成的路径叫交替路。

增广路:从一个未匹配的点开始,依次走过未匹配边,匹配边,未匹配边,匹配边,。。。。。。 如果最后的终点是一个未匹配点(即最后一条边是一条未匹配边),那么这条路就是一条增广路。而将增广路上的未匹配边和匹配边进行互换,就会使得匹配边多一条。

例如,图 5 中的一条增广路如图 6 所示(图中的匹配点均用红色标出):

6

增广路有一个重要特点:非匹配边比匹配边多一条。因此,研究增广路的意义是改进匹配

匈牙利算法思想:该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法

注:以下转自 http://blog.csdn.net/dark_scope/article/details/8880547(比较好理解)

通过数代人的努力,你终于赶上了剩男剩女的大潮,假设你是一位光荣的新世纪媒人,在你的手上有N个剩男,M个剩女,每个人都可能对多名异性有好感,如果一对男女互有好感,那么你就可以把这一对撮合在一起,你拥有的大概就是下面这样一张关系图,每一条连线都表示互有好感。


本着救人一命,胜造七级浮屠的原则,你想要尽可能地撮合更多的情侣,匈牙利算法的工作模式会教你这样做:

===============================================================================

一: 先试着给1号男生找妹子,发现第一个和他相连的1号女生还名花无主,got it,连上一条蓝线

===============================================================================

二:接着给2号男生找妹子,发现第一个和他相连的2号女生名花无主,got it

===============================================================================

三:接下来是3号男生,很遗憾1号女生已经有主了,怎么办呢?

我们试着给之前1号女生匹配的男生(也就是1号男生)另外分配一个妹子。

(黄色表示这条边被临时拆掉)

与1号男生相连的第二个女生是2号女生,但是2号女生也有主了,怎么办呢?我们再试着给2号女生的原配()重新找个妹子(注意这个步骤和上面是一样的,这是一个递归的过程)


此时发现2号男生还能找到3号女生,那么之前的问题迎刃而解了,回溯回去

2号男生可以找3号妹子~~~                  1号男生可以找2号妹子了~~~                3号男生可以找1号妹子

              

所以第三步最后的结果就是:

===============================================================================

四: 接下来是4号男生,很遗憾,按照第三步的节奏我们没法给4号男生腾出来一个妹子,我们实在是无能为力了

===============================================================================

这就是匈牙利算法的流程,其中找妹子是个递归的过程,最最关键的字就是“腾”字

匈牙利算法的另一个案例:(理解思想)

   1、起始没有匹配 

二分图最大匹配---匈牙利算法(Hungarian Algorithm)_第7张图片

   2、选中第一个x点找第一跟连线 

二分图最大匹配---匈牙利算法(Hungarian Algorithm)_第8张图片

   3、选中第二个点找第二跟连线

二分图最大匹配---匈牙利算法(Hungarian Algorithm)_第9张图片

   4、发现x3的第一条边x3y1已经被人占了,找出x3出发的的交错路径x3-y1-x1-y4,把交错路中已在匹配上的边x1y1从匹配中去掉,剩余的边x3y1 x1y4加到匹配中去

二分图最大匹配---匈牙利算法(Hungarian Algorithm)_第10张图片

   5、同理加入x4,x5。 

 匈牙利算法可以深度有限或者广度优先,本文的示例采用深度优先,即x3找y1,y1已经有匹配,则找交错路。若是广度优先,应为:x3找y1,y1有匹配,x3找y2。 

python代码实现:

#匈牙利算法求解最大匹配问题
def Matching(u):
    for i in range(1,m+1):#扫描B集合的每个顶点
        if Graph[u][i]==1 and used[i]==0:#x与i之间有边,并且i未被访问
            used[i]=1
            if B[i]==0 or Matching(B[i]):#i未被匹配,或者通过i节点可以找到增广路
                B[i]=u
                return True
            
    return False
        
        
while True:
    k,n,m=eval(input("\n请输入三个数以逗号隔开,分别代表边的个数、A集合元素个数、B集合元素个数:"))
    Graph=[[0 for e in range(0,m+1)] for j in range(0,n+1)]#存储图
    print("请输入k行,每行两个整数以逗号隔开,表示一条边")
    for i in range(0,k):
        a,b=eval(input())
        Graph[a][b]=1
    #print(Graph)
    B=[0 for i in range(0,m+1)]#用来存储B匹配的对象
    used=[0 for i in range(0,m+1)]
    ans=0
    for i in range(1,n+1):
        used=[0 for i in range(0,m+1)]#每次匹配前都清零
        if Matching(i):
            ans=ans+1

    print("最大匹配是:",ans)


 

 

 



 

 

 

 

你可能感兴趣的:(二分图)