Python中匈牙利算法

作为一名信息研究员或编程设计师,您可能会在很多时候遇到简化困难,他们要求以最佳方式将资源分配给任务。其中一个问题是任务问题,其中我们应该根据资产的成本或价值决定如何最好地将资产分配给练习。真正解决这个问题的一种流行方法是匈牙利计算。在本文中,我们将研究匈牙利计算并将其设置为 Python 中的常规情况。

什么是分配问题?
您可以将任务问题描述如下:在给定一堆资产和一堆任务的情况下,我们应该选择限制总费用或增加任务总价值的任务,其中每项资产只能用于一项任务,而每项任务只能用于一项任务。分配只需要一项资产。这个问题出现在各个地区,包括匹配问题、工作预订和创作安排。
直接任务问题代表需要增加可利用的资产数量,同时限制现金支出。作为一个轮廓,请考虑下面显示的 2D 网格,其中每条线与特定供应商进行比较,每个部分与雇用该供应商实现特定体面的费用进行比较。每个供应商都仅限于在形成这些产品中的一种产品方面拥有一定的专业知识。对于晶格中的每个线段和线,只能选择单个组件,并且所选择的事物的完成应该是有限的(有限的成本使用)。

匈牙利计算:概要
在多项式时间内解决任务问题的一个强大策略是匈牙利计算,有时被称为 Kuhn-Munkres 计算。为了识别理想的任务,它利用组合增强系统。该方法利用“对偶”技术来解决这个问题,并依赖于扩大双边组织中的路径。

匈牙利计算用于确定理想任务的阶段如下:

  • 创建成本矩阵:通过构建一个网格来创建费用矩阵,该网格包含每项资产的一条线、每项任务的一个部分以及利用该资产完成该工作的费用或收益的组成部分。
  • 初始化分配矩阵:为了显示企业的资产比例,请创建第二个网格,其中包含最初填充零的费用框架的各个方面。
  • 归约矩阵:为了简化它以区分最佳任务,请将线和段归约应用于费用网络。在此阶段,应分别从相关栏和节中的剩余内容中扣除每行和段中最小的组成部分。
  • 找到最初的可行解决方案:通过将资产分配给各个职业来找到主要的有用安排,以确保任何一条线或部门都没有超过一项任务。为此,请通过缩小框架的零点来定义边界。
  • 增强任务:要完成任务,请在缩小的框架中找到最小的未覆盖组件,如果主要答案不是最理想的答案,则从任何剩余的未覆盖组件中扣除它。之后将其添加到两行覆盖的每个组件中。继续这样做,直到找到最好的任务。
  • 改进分配:如果任务还不是很出色,请更改网络线路,为道路扩展开辟更多机会。之前的系统应该被重新修改,直到获得理想的任务。
  • 提取作业:当理想的任务被区分出来后,将其从任务格中消除,并将其作为问题的解决方案。

Python 执行匈牙利计算
scipy 包有一个名为 Linear_sum_assignment 的功能,它应用匈牙利技术来确定任务问题,允许我们在 Python 中执行匈牙利计算。这是应用它的方式的描述:

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_indices, col_indices = linear_sum_assignment(cost_matrix)  
# 提取最佳分配  ;
assignment = [(row, col) for row, col in zip (row_indices, col_indices)]  
print ("Optimal Assignment:")  
for a row, col in assignment:  
    print (f
"Resource {row} assigned to Task {col}")  

在本示例中,我们建立了一个成本矩阵,以说明将三项资源分配给三项任务的相关费用。然后使用 linear_sum_assignment 函数找出最佳分配。理想分配的行和列索引包含在函数返回的 row_indices 和 col_indices 两个数组中。然后提取赋值并打印结果。

给定一个二维数组,arr 的大小为 N*N,其中 arr[j] 表示第 i 个工作人员完成第 j 个工作的费用。任何员工都可能被指派执行任何任务。目标是划分任务,以便每个工人一次只专注于一项任务,同时最大限度地降低任务的总体成本。


例如2

输入: arr[][] = {{3, 5}, {10, 1}}
输出: 4
说明:理想的分配是将工作 1 分配给第一名员工,工作 2 分配给第二名员工。  
因此,理想的价格是 3 + 1 = 4。

输入:arr[][] = {{2500, 4000, 3500}, {4000, 6000, 3500}, {2000, 4000, 2500}}
输出: 4
解释:最佳分配是给第二个工人工作 2,给第三个工人工作 3,给第三个工人工作 1。
因此,最佳成本为 3 + 1 = 4。

输入:arr[][] = {{2500, 4000, 3500}, {4000, 6000, 3500}, {2000, 4000, 2500}}
输出: 4
说明:最佳分配是将工作 2 分配给第 1 名工人,工作 3 分配给第 2 名工人,工作 1 分配给第 3 名工人。  
因此,最佳成本为 4000 + 3500 + 2000 = 9500。

本文描述了此问题的许多解决方案。
方法:将使用匈牙利算法来解决这个问题。该算法的工作原理如下:

  • 找到矩阵每一行中的最小元素,并将其从该行中的每个其他元素中减去。
  • 应对每一列重复步骤 1。
  • 使用尽可能少的水平线和垂直线将矩阵完全填充为零。
  • 最优性测试:如果覆盖线的最少数量为 N,则可以实现最优分配。否则,如果线少于 N,则不会发现最优分配,必须执行步骤 5。
  • 找到未被线条包围的最小条目。该条目将从每个未覆盖的行中减去并添加到每个覆盖的列中。返回步骤 3。

为了理解这一策略,请看下面的例子:

假设二维数组为

2500 4000 3500
4000 6000 3500
2000 4000 2500

步骤 1:从每一行中减去最小值。第 1、2 和 3 行分别减去 2、3 和 2000。  

0 1500 1000
500 2500 0
0 2000 500

步骤 2:从每列中减去最小值。第 1、2 和 3 列分别扣除 0、1500 和 0。

0 0 1000
500 1000 0
0 500 500

步骤 3:用尽可能少的横线和竖线将所有零包围起来。  


步骤 4:发现理想的分配,因为需要三行才能覆盖每个零。  

2500 4000 3500
 4000 6000 3500
 2000 4000 2500

因此,最佳成本为 4000 + 3500 + 2000 = 9500

我们的目标是利用 dlib 软件包中的 max_cost_assignment() 函数来构建上述程序。匈牙利算法(有时也称为库恩-蒙克雷斯算法)就是在这个函数中实现的,完成该算法需要 O(N^3) 的时间。理想赋值问题迎刃而解。

上述策略的应用如下:

# Python program for the method described above  
import dlib  
# 目标是确定什么是最好的。 
个人被分配到职业,以便 
任务的整体成本保持在最低 ;
def minCost(arr):   
   # 使用函数 max_cost_assignment()  
    # 并保留任务;
    assignment = dlib.max_cost_assignment(arr)  
   # 打印最佳成本  ;
    print(dlib.assignment_cost(arr, assignment))  
# Driver Code   
# Given 2D array  
arr = dlib.matrix([[2, 5], [10, 1]])   
# Function Calling  
minCost(arr)  

输出:5


时间复杂性:O(N^3)
辅助空间: O(N^2)O(N^2)

结论
匈牙利战略是快速解决任务问题的成功方法。该计算方法通过在双向组织中使用扩展路径来限制成本或提高价值,从而决定最佳任务。在此,我们对匈牙利技术进行了分析,并利用 scipy bundle 在 Python 中进行了执行。作为一名信息研究员或程序员,你现在可以利用这项技能,在自己的工作中使用匈牙利计算来处理学校作业问题。

匈牙利策略只是各种先进计算方法中的一种;在为特定情况选择最佳计算方法之前,了解制约因素和问题背景是基础。