匈牙利算法再读 python

匈牙利算法

1.增广路径:看了好多对增广路径解释的都不清楚,这篇我觉的解释非常清楚。

https://blog.csdn.net/reid_zhang1993/article/details/44080167

2.最大匹配,最优匹配

最大是实现边路最多,最优是带加权的最大匹配。

3.讲解实例

a.DFS

                    

注意return位置!!!

从A开始,visited置0, ,寻找增广路径,进入Y队列循环,E,if  edge[A][E]==1 and visited[E]==0, if cy[E]==-1,匹配A、E,返回。

此时匹配为A、E

B,visited置0, 寻找增广路径,进入Y队列循环,E,if  edge[B][E]==1 and visited[E]==0,不匹配。

                                                                                F ,if  edge[B][F]==1 and visited[E]==0,if cy[F]==-1匹配B、F。返回

此时匹配为A、E;B、F

C,visited置0, 寻找增广路径,进入Y队列循环,E,if  edge[C][E]==1 and visited[E]==0,匹配。if cy[E]==-1,不满足,进入else,删掉A、E匹配,再递归,进入A的路径寻找。如果能找到,则返回匹配。

此时匹配为B、F;A、G;C、E

D,visited置0, 寻找增广路径,进入Y队列循环,E,if  edge[D][E]==1 and visited[E]==0,不匹配

                                                                                F,if  edge[D][E]==1 and visited[E]==0,不匹配

                                                                                G,if  edge[D][E]==1 and visited[E]==0,匹配。if cy[G]==-1,不满足,进入else,删掉A、G匹配,再递归,进入A的路径寻找。如果能找到,则返回匹配。D-G-A-E-C-H,能找到增广路径,返回匹配。

M=[]
class DFS_hungary():

    def __init__(self, nx, ny, edge, cx, cy, visited):
        self.nx, self.ny=nx, ny
        self.edge = edge
        self.cx, self.cy=cx,cy
        self.visited=visited

    def max_match(self):   #X序列循环匹配,从A-B-C-D...
        res=0
        for i in self.nx:
            print(i)
            if self.cx[i]==-1:
                for key in self.ny:         # 将visited置0表示未访问过
                    self.visited[key]=0
                res+=self.path(i)
                print(nx,ny)
                print(edge)
                print(cx,cy)
                print(visited)
                print('This is M:',M)
        return res,M

    def path(self, u):    #寻找增广路径
        for v in self.ny:
            if self.edge[u][v] and (not self.visited[v]):
                self.visited[v]=1
                print('---')
                print(self.visited)
                print('---')
                if self.cy[v]==-1:
                    self.cx[u] = v
                    self.cy[v] = u
                    M.append((u,v))
                    return 1
                else:
                    M.remove((self.cy[v], v))
                    if self.path(self.cy[v]):    #递归
                        self.cx[u] = v
                        self.cy[v] = u
                        M.append((u, v))
                        return 1
        return 0

if __name__ == '__main__':
    nx, ny = ['A', 'B', 'C', 'D'], ['E', 'F', 'G', 'H']
    edge = {'A':{'E': 1, 'F': 0, 'G': 1, 'H':0}, 'B':{'E': 0, 'F': 1, 'G': 0, 'H':1}, 'C':{'E': 1, 'F': 0, 'G': 0, 'H':1}, 'D':{'E': 0, 'F': 0, 'G': 1, 'H':0}} # 1 表示可以匹配, 0 表示不能匹配
    cx, cy = {'A':-1,'B':-1,'C':-1,'D':-1}, {'E':-1,'F':-1,'G':-1,'H':-1}
    visited = {'E': 0, 'F': 0, 'G': 0,'H':0}

    print (DFS_hungary(nx, ny, edge, cx, cy, visited).max_match())

'''
nx,ny表示X、Y序列
edge 表示匹配初始关系
cx、cy表示匹配过程中的配对关系
visited 表示是否访问过。???
在此过程中注意return的使用位置,很有讲究。
'''
'''
运行结果
A
---
{'F': 0, 'G': 0, 'H': 0, 'E': 1}
---
['A', 'B', 'C', 'D'] ['E', 'F', 'G', 'H']
{'D': {'F': 0, 'G': 1, 'H': 0, 'E': 0}, 'C': {'F': 0, 'G': 0, 'H': 1, 'E': 1}, 'A': {'F': 0, 'G': 1, 'H': 0, 'E': 1}, 'B': {'F': 1, 'G': 0, 'H': 1, 'E': 0}}
{'D': -1, 'C': -1, 'A': 'E', 'B': -1} {'F': -1, 'G': -1, 'H': -1, 'E': 'A'}
{'F': 0, 'G': 0, 'H': 0, 'E': 1}
This is M: [('A', 'E')]
B
---
{'F': 1, 'G': 0, 'H': 0, 'E': 0}
---
['A', 'B', 'C', 'D'] ['E', 'F', 'G', 'H']
{'D': {'F': 0, 'G': 1, 'H': 0, 'E': 0}, 'C': {'F': 0, 'G': 0, 'H': 1, 'E': 1}, 'A': {'F': 0, 'G': 1, 'H': 0, 'E': 1}, 'B': {'F': 1, 'G': 0, 'H': 1, 'E': 0}}
{'D': -1, 'C': -1, 'A': 'E', 'B': 'F'} {'F': 'B', 'G': -1, 'H': -1, 'E': 'A'}
{'F': 1, 'G': 0, 'H': 0, 'E': 0}
This is M: [('A', 'E'), ('B', 'F')]
C
---
{'F': 0, 'G': 0, 'H': 0, 'E': 1}
---
---
{'F': 0, 'G': 1, 'H': 0, 'E': 1}
---
['A', 'B', 'C', 'D'] ['E', 'F', 'G', 'H']
{'D': {'F': 0, 'G': 1, 'H': 0, 'E': 0}, 'C': {'F': 0, 'G': 0, 'H': 1, 'E': 1}, 'A': {'F': 0, 'G': 1, 'H': 0, 'E': 1}, 'B': {'F': 1, 'G': 0, 'H': 1, 'E': 0}}
{'D': -1, 'C': 'E', 'A': 'G', 'B': 'F'} {'F': 'B', 'G': 'A', 'H': -1, 'E': 'C'}
{'F': 0, 'G': 1, 'H': 0, 'E': 1}
This is M: [('B', 'F'), ('A', 'G'), ('C', 'E')]
D
---
{'F': 0, 'G': 1, 'H': 0, 'E': 0}
---
---
{'F': 0, 'G': 1, 'H': 0, 'E': 1}
---
---
{'F': 0, 'G': 1, 'H': 1, 'E': 1}
---
['A', 'B', 'C', 'D'] ['E', 'F', 'G', 'H']
{'D': {'F': 0, 'G': 1, 'H': 0, 'E': 0}, 'C': {'F': 0, 'G': 0, 'H': 1, 'E': 1}, 'A': {'F': 0, 'G': 1, 'H': 0, 'E': 1}, 'B': {'F': 1, 'G': 0, 'H': 1, 'E': 0}}
{'D': 'G', 'C': 'H', 'A': 'E', 'B': 'F'} {'F': 'B', 'G': 'D', 'H': 'C', 'E': 'A'}
{'F': 0, 'G': 1, 'H': 1, 'E': 1}
This is M: [('B', 'F'), ('C', 'H'), ('A', 'E'), ('D', 'G')]
(4, [('B', 'F'), ('C', 'H'), ('A', 'E'), ('D', 'G')])
'''

b.BFS

def BFS_hungary(g,Nx,Ny,Mx,My,chk,Q,prev):
    res=0
    for i in range(Nx):
        print('第几轮:',i)
        if Mx[i]==-1:
            qs=qe=0
            print('qs:',qs,'qe:',qe)
            Q[qe]=i
            print('qe:',qe,'Q:',Q)
            qe+=1
            print('qe:',qe)
            prev[i]=-1
            print('prev',prev)
            flag=0
            while(qs<qe and not flag):
                u=Q[qs]
                print('u:',u)
                for v in range(Ny):
                    print('----------')
                    if flag:continue
                    if g[u][v] and chk[v]!=i:
                        chk[v]=i
                        print('v:',v,'chk:',chk)
                        Q[qe]=My[v]
                        print('qe',qe,'Q',Q)
                        qe+=1
                        print('qe',qe)
                        if My[v]>=0:
                            prev[My[v]]=u
                            print('prev',prev)
                            print('lala')
                        else:
                            flag=1
                            d,e=u,v
                            print('d:',d,'e:',e)
                            while d!=-1:
                                t=Mx[d]
                                print('t:',t)
                                Mx[d]=e
                                print('d:',d,'Mx',Mx)
                                My[e]=d
                                print('e:',e,'My:',My)
                                d=prev[d]
                                print('d:',d)
                                e=t
                                print('e:',e)
                    print('-----')
                qs+=1
            if Mx[i]!=-1:
                res+=1
        print('Mx:',Mx,'My:',My,'chk:',chk,'Q:',Q,'prev',prev)
        print('----------------------------------------------------------------------------------')
    return res

if __name__ == '__main__':
       g=[[1,0,1,0],[0,1,0,1],[1,0,0,1],[0,0,1,0]]
       Nx=4
       Ny=4
       Mx=[-1,-1,-1,-1]
       My=[-1,-1,-1,-1]
       chk=[-1,-1,-1,-1]
       Q=[0 for i in range(5)]
       #原代码
       # Q=[0 for i in range(100)]
       prev=[0,0,0,0]
       print(BFS_hungary(g,Nx,Ny,Mx,My,chk,Q,prev))

'''
Mx 为以X序列对应的Y的序号
My 为以Y序列对应的X的序号
chk,  v   该轮对应的匹配关系以Y为底
qe的数目代表v运行的次数,qe=1,代表v循环了一次。
  qe=0  qe=1    qe=2
Q[ u,   My[v],  My[v],  0  ,   0]
prev[,,,]代表是否访问过  -1,,-1,-1,-1  代表此前没有访问过,2 代表访问过两次。有两个X访问。
'''

'''
运行结果:
第几轮: 0
qs: 0 qe: 0
qe: 0 Q: [0, 0, 0, 0, 0]
qe: 1
prev [-1, 0, 0, 0]
u: 0
----------
v: 0 chk: [0, -1, -1, -1]
qe 1 Q [0, -1, 0, 0, 0]
qe 2
d: 0 e: 0
t: -1
d: 0 Mx [0, -1, -1, -1]
e: 0 My: [0, -1, -1, -1]
d: -1
e: -1
-----
----------
----------
----------
Mx: [0, -1, -1, -1] My: [0, -1, -1, -1] chk: [0, -1, -1, -1] Q: [0, -1, 0, 0, 0] prev [-1, 0, 0, 0]
----------------------------------------------------------------------------------
第几轮: 1
qs: 0 qe: 0
qe: 0 Q: [1, -1, 0, 0, 0]
qe: 1
prev [-1, -1, 0, 0]
u: 1
----------
-----
----------
v: 1 chk: [0, 1, -1, -1]
qe 1 Q [1, -1, 0, 0, 0]
qe 2
d: 1 e: 1
t: -1
d: 1 Mx [0, 1, -1, -1]
e: 1 My: [0, 1, -1, -1]
d: -1
e: -1
-----
----------
----------
Mx: [0, 1, -1, -1] My: [0, 1, -1, -1] chk: [0, 1, -1, -1] Q: [1, -1, 0, 0, 0] prev [-1, -1, 0, 0]
----------------------------------------------------------------------------------
第几轮: 2
qs: 0 qe: 0
qe: 0 Q: [2, -1, 0, 0, 0]
qe: 1
prev [-1, -1, -1, 0]
u: 2
----------
v: 0 chk: [2, 1, -1, -1]
qe 1 Q [2, 0, 0, 0, 0]
qe 2
prev [2, -1, -1, 0]
lala
-----
----------
-----
----------
-----
----------
v: 3 chk: [2, 1, -1, 2]
qe 2 Q [2, 0, -1, 0, 0]
qe 3
d: 2 e: 3
t: -1
d: 2 Mx [0, 1, 3, -1]
e: 3 My: [0, 1, -1, 2]
d: -1
e: -1
-----
Mx: [0, 1, 3, -1] My: [0, 1, -1, 2] chk: [2, 1, -1, 2] Q: [2, 0, -1, 0, 0] prev [2, -1, -1, 0]
----------------------------------------------------------------------------------
第几轮: 3
qs: 0 qe: 0
qe: 0 Q: [3, 0, -1, 0, 0]
qe: 1
prev [2, -1, -1, -1]
u: 3
----------
-----
----------
-----
----------
v: 2 chk: [2, 1, 3, 2]
qe 1 Q [3, -1, -1, 0, 0]
qe 2
d: 3 e: 2
t: -1
d: 3 Mx [0, 1, 3, 2]
e: 2 My: [0, 1, 3, 2]
d: -1
e: -1
-----
----------
Mx: [0, 1, 3, 2] My: [0, 1, 3, 2] chk: [2, 1, 3, 2] Q: [3, -1, -1, 0, 0] prev [2, -1, -1, -1]
----------------------------------------------------------------------------------
4
'''

c.BFS与DFS比较

https://www.cnblogs.com/wzl19981116/p/9397203.html

BFS节约时间,浪费空间。DFS节约空间,浪费时间。

 

代码部分来自

https://www.cnblogs.com/jamespei/p/5555734.html

感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值