匈牙利算法详解与实现

news/2024/9/24 7:48:36/

匈牙利算法是一种高效的二分图最大匹配最优分配算法,常用于解决任务分配问题,例如将工人分配给任务以最小化成本。该算法通过多步矩阵操作和调整来寻找最优匹配,保证了分配成本的最小化。


算法概述

1. 矩阵减法

首先对矩阵进行行列减法:

  • 行减法:每行减去该行的最小值,使每行至少有一个零。
  • 列减法:在行减法的基础上,每列再减去该列的最小值,使每列至少有一个零。

2. 划线覆盖零元素

用尽量少的直线(横线或竖线)覆盖矩阵中的所有零元素。如果划线数量等于矩阵维度,则已找到最优解,否则进入下一步。

3. 调整矩阵

找到未被线覆盖的最小元素并调整矩阵:

  • 未被覆盖的元素减去最小值。
  • 交叉线的交点元素加上最小值。
  • 其他已被线覆盖的元素保持不变。

4. 寻找匹配

使用调整后的矩阵寻找最优匹配。优先选择那些行或列中只有一个零的元素进行匹配。

5. 计算最小成本

根据原始成本矩阵,计算匹配方案的总成本。


例子:工人与任务分配问题

假设有3个工人和3个任务,分配成本如下:

任务1任务2任务3
工人1413
工人2205
工人3322

1. 行和列减法

行减法:
  • 工人1:4, 1, 30, 1, 0
  • 工人2:2, 0, 50, 0, 5
  • 工人3:3, 2, 20, 2, 2

矩阵变为:

任务1任务2任务3
工人1010
工人2005
工人3022
列减法:
  • 任务1列不变:0, 0, 0
  • 任务2列不变:1, 0, 2
  • 任务3列不变:0, 5, 2

调整后:

任务1任务2任务3
工人1010
工人2005
工人3022

2. 划线覆盖零元素

通过观察,使用两条线就能覆盖所有零:

  • 一条线覆盖任务1列。
  • 一条线覆盖工人2的行。

3. 调整矩阵

最小未覆盖元素为 1。对矩阵调整如下:

  • 未被覆盖的元素减去 1
  • 交点元素加 1

调整后矩阵:

任务1任务2任务3
工人1101
工人2004
工人3011

4. 寻找最优匹配

开始匹配:

  • 工人1分配任务2,删除该行列。
  • 工人2分配任务1,删除该行列。
  • 工人3分配任务3。

5. 计算最小总成本

总成本为:

  • 工人1 → 任务2,成本为 1
  • 工人2 → 任务1,成本为 2
  • 工人3 → 任务3,成本为 2

总成本:1 + 2 + 2 = 5


Python实现

使用 scipy 库的 linear_sum_assignment 方法快速实现匈牙利算法

import numpy as np
from scipy.optimize import linear_sum_assignment# 成本矩阵
cost_matrix = np.array([[4, 1, 3],[2, 0, 5],[3, 2, 2]
])# 求解最优分配
row_ind, col_ind = linear_sum_assignment(cost_matrix)# 输出结果
print("工人分配到任务的对应关系:")
for i, j in zip(row_ind, col_ind):print(f"工人 {i + 1} 分配到任务 {j + 1}")# 计算总成本
total_cost = cost_matrix[row_ind, col_ind].sum()
print(f"总成本: {total_cost}")

输出结果:

工人分配到任务的对应关系:
工人 1 分配到 任务 2
工人 2 分配到 任务 1
工人 3 分配到 任务 3
总成本: 5

工人多于任务的情况

当工人多于任务时,可以通过向矩阵添加虚拟任务来平衡工人和任务的数量。虚拟任务的成本可以设为0或极大值,以确保虚拟任务不会被实际分配。

例如,4个工人和3个任务的成本矩阵如下:

任务1任务2任务3
工人1413
工人2205
工人3322
工人4643

为了平衡,添加虚拟任务4,矩阵变为:

任务1任务2任务3任务4 (虚拟任务)
工人14130
工人22050
工人33220
工人46430

调整后可继续使用匈牙利算法进行求解。

Code

AI_With_NumPy
此项目汇集了更多AI相关的代码实现,供大家学习使用,欢迎点赞收藏👏🏻

备注

个人水平有限,有问题随时交流~


http://www.ppmy.cn/news/1529716.html

相关文章

【JavaEE】——多重锁,死锁问题和解决思路

阿华代码,不是逆风,就是我疯,你们的点赞收藏是我前进最大的动力!!希望本文内容能够帮助到你! 目录 一:加锁的“可重入性” 1:问题引入 2:问题分析 3:可重…

新建flask项目,配置入口文件,启动项目

pycharm新建flask项目时,会提供一个创建flask项目的导向,自动设置虚拟环境,并且安装flask及其依赖而vscode新建flask项目时,需要手动设置虚拟环境并安装flask,需要在终端使用pip install flask命令来安装flask及其依赖…

策略模式与工厂模式的区别

《策略模式与工厂模式的区别》 策略模式(Strategy Pattern) 和 工厂模式(Factory Pattern) 都是常见的设计模式,虽然它们在设计目标上有一些相似之处,如解耦代码、增强扩展性,但它们的应用场景和…

STM32G474的SPI工作在从机模式

STM32G474的SPI工作在从机模式,我们令SPI1工作在主机模式,SPI2工作在从机模式中,实现数据数据互传。本测试只讲解SPI一主一从通讯,至于一主多从,程序中有说明。 SPI1外设用作主机,其接口:将SPI1…

UE5学习笔记22-武器瞄准和武器自动开火

0、一些疑问的记录 1.UUserWidget类和AHUD类的区别。两者都是关于界面显示的类。 实践: 想让界面和用户有交互使用UUserWidget,如果不要交互只是显示使用AHUD类,例如使用UUserWidget类制作开始界面,游戏开始,游戏设置&…

微服务--Gateway网关

在微服务架构中,Gateway(网关)是一个至关重要的组件,它扮演着多种关键角色,包括路由、负载均衡、安全控制、监控和日志记录等。 Gateway网关的作用 统一访问入口: Gateway作为微服务的统一入口&#xff0c…

【LeetCode】【C++】27. 移除元素 80.删除有序数组中的重复项Ⅱ

27. 移除元素 题目描述 详见LeetCode 27. 移除元素。 这是一道特别水的题,但是我第一时间没有想到正确的解答思路。 题目描述可以简述为,给定数组nums和元素val,原地删除nums中等于val的元素,并返回nums中不等于val元素的个数…

新提案:C++将变得内存安全

革命性的提案:C 将添加借用检查、生命周期、mut、sendsync 在遭受内存安全棒的打击两年后,C 社区发布了一项提案,以帮助开发人员编写更不容易受到攻击的代码。 Safe C 扩展提案旨在解决易受攻击的编程语言的致命弱点,即确保代码…