指派过程中,匈牙利算法存在的问题(待解决)

在使用匈牙利算法求解车辆调度问题时,采用固定矩阵大小,随机生成矩阵数值的形式来求解,发现在矩阵取到特定数值时,匈牙利算法则无法求解或者生成错误的值。

1.错误情况复现

具体出现情况复现如下:
(如果想看问题原因,可以直接跳到第2小节;解决方法见第3小节)
以3*3矩阵为例,我在运行时产生的矩阵权值为:

    test = [
        [8, 10, 11],
        [0, 6, 11],
        [3, 9, 12]]

然后根据匈牙利算法的过程进行每行减去此行的最小值,然后每列减去此列的最小值操作后,得到的矩阵(这里记作test0)为

test0 = [
	   [0, 0, 0],
	   [0, 4, 8],
       [0, 4, 6]]

接下来就进行“试指派”过程,也就是“划线”寻找最小零元素的过程。

这里第一步要统计每一行中零元素的个数,从而找到最小零元素的行,从而标记得到“独立零元素”,并进行划线。这里很显然,第2行和第3行的零元素最少,均为1。

为了方便,这里假设取第2行为最少零元素的行,并标记第2行第1列的数字为“独立零元素”
然后按照同样的方法,标记第1行第2列的数字为“独立零元素”,从而完成第1次试指派。

为了直观表示指派后的情况,将独立零元素所在矩阵位置标记为1,非独立零元素所在矩阵位置标记为-1,其他元素所在位置标记为0,得到test1矩阵,如下所示:

test1 = [
	   [-1, 1, -1],
	   [1, 0, 0],
       [-1, 0, 0]]

很显然,第1次试指派只标记了2个“独立零元素”,小于矩阵的维数(3),因此需要进行调整。
下一步需要将没有“独立零元素”的行进行打勾,将打勾的行中所含零元素的列进行打勾,对所有打勾的列中所含“独立零元素”的行进行打勾;
因此,打勾的行为第2行和第3行,打勾的列为第1列。
接着,对打勾的列(第1列)和没有打勾的行(第1行)进行划线,得到覆盖矩阵中所有的零元素最少的划线。然后对矩阵进行调整。(得到的矩阵为test2,并且将被线划到(不在交叉点)的数都记作0,划线交叉点的数记为1,其它数字与test0相同,以便下一步更容易理解)

test2 = [
	   [1, 0, 0],
	   [0, 4, 8],
       [0, 4, 6]]

在矩阵调整中,找到未被线划到的数中最小的,这里为4。
在调整时,将没有被线划到的数减去4,将划线交叉点(这里是第1行第1列)加上4,得到新矩阵test3

test3 = [
	   [4, 0, 0],
	   [0, 0, 4],
       [0, 0, 2]]

然后对新矩阵进行类似上面的试指派过程,这里不再赘述,直接展示试指派结果。(类似上面的test2矩阵,这里为test4)

test4 = [
	   [0, 0, 0],
	   [0, 0, 4],
       [0, 0, 2]]

2.错误原因所在

此时就是问题的关键点所在了:
由于没被划线的数中最小的数为0,因此不会对test矩阵进行调整!
此时test4矩阵就不会进行继续更新,因此无论调度多少次,算法始终卡在一个死循环中,无法跳出循环。

3.解决方法

使用Python自带的算法进行求解,代码如下:

from numpy import array
from scipy.optimize import linear_sum_assignment

cost = ([[8, 10, 11], [0, 6, 11], [3, 9, 12]])
cost = array(cost)
row_ind, col_ind = linear_sum_assignment(cost)

# 调度方案
print(row_ind)  # 开销矩阵对应的行索引
print(col_ind)  # 对应行索引的最优指派的列索引

# 总权值
potential = cost[row_ind, col_ind].sum()
print("总权值:", potential)
print("-" * 60)

可以得到正确的运算结果,如下图:

[0 1 2]
[2 0 1]
总权值: 20
------------------------------------------------------------

参考文章:
超详细!!!匈牙利算法流程以及Python程序实现!!!通俗易懂

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值