二分图匹配相关算法

Hungarian 算法

https://article.itxueyuan.com/Aeava9

在这里插入图片描述在这里插入图片描述在这里插入图片描述
程序运行结果:

--x=0--
1 - 1
--x=1--
1 - 1
2 - 2
--x=2--
3 - 1
1 - 2
2 - 3
--x=3--
3 - 1
1 - 2
2 - 3
import numpy as np



def node_map_to_adj_matrix(node_map):
    L = max(node_map.keys())
    adj=np.zeros([L,L],dtype=np.int32)
    for u in node_map:
        for v in node_map[u]:
            adj[u-1,v-1]=1
    return adj

def dfs(x:int, N:int, adj, vis, match)->bool:
    '''女生 X 男生 Y
    :param N:
    :param x:
    :param adj:
    :param vis: Y是否被使用
    :param match: 记录Yi选择的X编号,未被选则0
    :return:
    '''
    # 遍历所有Y
    x=int(x)
    for y in range(N):
        # 如果xy联通并且y没有被使用
        if adj[x,y]==1 and vis[y]==0:
            vis[y]=1
            # 如果choice[y]没有被占用或者能把占用boy[i]的人换一个连线,短路原则: 如果没有被占用则不会执行后面的部分
            if match[y]==-1 or dfs(match[y], N, adj, vis, match):
                match[y]=x
                return True
    return False

def print_edge_by_choice(choice):
    for i,e in enumerate(choice):
        if e!=-1:
            e=int(e)
            print(e+1,'-',i+1)

def Hungarian_main(adj, N):
    choice = -1 * np.ones([N])
    for x in range(4):
        print(f'--x={x:d}--')
        vis=np.zeros([N])
        ret=dfs(x,N,adj,vis,choice)
        # print(choice)
        print_edge_by_choice(choice)


if __name__ == '__main__':
    node_map = {
        1: [1, 2],
        2: [2, 3],
        3: [1, 2],
        4: [3]
    }
    adj=node_map_to_adj_matrix(node_map)
    N=4
    Hungarian_main(adj, N)



KM 算法

https://blog.csdn.net/chenshibo17/article/details/79933191

在这里插入图片描述在这里插入图片描述在这里插入图片描述

import numpy as np


def node_map_to_adj_matrix(node_map):
    L = max(node_map.keys())
    adj = np.zeros([L, L], dtype=np.int32)
    for u in node_map:
        for v, w in node_map[u]:
            adj[u - 1, v - 1] = w
    return adj


def dfs(x: int, N: int, ex_x, ex_y, vis_x, vis_y, match, slack) -> bool:
    x=int(x)
    vis_x[x] = True
    for y in range(N):
        if vis_y[y]:
            continue
        gap = ex_x[x] + ex_y[y] - adj[x][y]
        if gap == 0:
            vis_y[y] = True
            if match[y] == -1 or dfs(match[y], N, ex_x, ex_y, vis_x, vis_y, match, slack):
                match[y] = x
                return True
        else:
            slack[y] = min(slack[y], gap)
    return False


def KM_main(adj: np.ndarray, N):
    ex_x = adj.max(axis=1)
    ex_y = np.zeros([N], dtype='int')
    match = np.ones([N], dtype='int') * -1
    for x in range(N):
        slack = np.ones([N], dtype='int') * np.inf
        while True:
            vis_x = np.zeros([N], dtype='bool')
            vis_y = np.zeros([N], dtype='bool')
            # 如果匹配成功,退出
            if dfs(x, N, ex_x, ex_y, vis_x, vis_y, match, slack):
                break
            d = np.inf
            for j in range(N):
                if not vis_y[j]:
                    d=min(d,slack[j])
            print('d',d)
            for j in range(N):
                if vis_x[j] :
                    ex_x[j]-=d
                if vis_y[j]:
                    ex_y[j]+=d
                else:
                    slack[j]-=d
        print(match)


if __name__ == '__main__':
    node_map = {
        1: [(1, 3), (3, 4)],
        2: [(1, 2), (2, 1), (3, 3)],
        3: [(3, 5)]
    }
    N = 3
    adj = node_map_to_adj_matrix(node_map)
    KM_main(adj, N)

发布了281 篇原创文章 · 获赞 35 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/TQCAI666/article/details/103341851
今日推荐