Python 矩阵的最大值 python计算矩阵_javascript

考虑以下问题:

由于疏忽,您的房屋急需维修。 自然地,您外出并获得有关重塑和修复需要完成的操作的报价。 假设您收到的四个引号如下所示:




Python 矩阵的最大值 python计算矩阵_python_02

考虑到所有因素,这似乎很合理。 我们自然会选择Susan,因为她为我们提供了最佳的整体价格。 但是,另一种解决方案可能是将我们需要完成的工作分解为单个项目。 然后我们可以从承包商处获得每个维修项目的价格。 这将通过两种方式更加有益:

  1. 我们可以节省时间,因为所有承包商都可以同时处理每个维修项目,并且可以更快地完成整个项目。
  2. 通过根据承包商的最低物料成本雇用承包商,我们也可能会获得更好的价格。

看看下面的图表,这些单独的价格可能是什么样的:




Python 矩阵的最大值 python计算矩阵_最小值_03

在执行此操作时,我们需要牢记两件事:

  1. 我们可能只想雇用一名承包商从事一项工作,以最大限度地节省时间。
  2. 这意味着我们不能使用同一承包商两次,并且自然地,我们在任何时候都不会有两个承包商从事同一工作。

例如,我们可以选择以下内容:




Python 矩阵的最大值 python计算矩阵_python_04

通过使用此策略,我们可以将工作分散到4个承包商中,从而可以最大程度地减少时间,但也可以通过每个维修项目雇用承包商来最大程度地降低成本。 尽管这看起来很简单,但是如果我们有更多的承包商可供选择,或者要考虑更多的维修工作,则可能很难计算。 幸运的是,有一个很好的公式可以解决此类问题。 我将使用一种称为“匈牙利方法”的方法。 匈牙利方法是一种组合优化算法,可以解决多项式时间内的赋值问题,并且可以预期以后的原始对偶方法。 它是由哈罗德·库恩(Harold Kuhn)于1955年开发和发布的,他将其命名为“匈牙利方法”,因为该算法主要基于两位匈牙利数学家:DénesKőnig和JenőEgerváry的早期著作。 使用伪代码解决此问题之后,我将介绍如何使用Python创建使用相同方法解决该问题的函数。 使用Python的优势在于,无论网格大小如何,我们都可以创建一个动态函数来求解方程。 如果像上面的示例中那样,我们决定增加更多的维修或获得更多的承包商报价,这可能会特别方便。 希望随着我们的研究,该策略的其他应用将变得显而易见。

匈牙利方法基本上包括三个步骤:

1.在每一列中找到最小值。

  • 将每列中的最小值转换为零。
  • 从同一列中的其他值减去每列中的最小值。

2.在每一行中找到最小值。

  • 如果该行中的最小值还不是零,则将其转换为零。
  • 再次从每行的剩余值中减去每行的最小值。

3.选择仅为零的行/列(如上例所示)。

这是此方法背后的原因:在每一列中,我们都有自己的工作。 每一列中的最小值代表无论如何我们必须支付的最低价格。 因此,通过将该值设置为零,我们可以从其他列值中减去该值。 这些行代表我们必须向承包商支付的价格。 最小行值表示我们必须向每个承包商支付的最低价格,并且类似地,将其设置为零可以使我们从行中的其他值中减去该价格。 让我们看一下如何将此方法应用于当前问题:

步骤1:将最低的列值设置为0。




Python 矩阵的最大值 python计算矩阵_javascript_05

在这里,我们可以看到每一列都有一个零。 但是,只有行1、3和4具有零,而行4具有2个零。 现在,我们将从剩余的列值中减去已转换为零的最低值。 在这里,我更新了第1列,从其余的列值中减去了最小值70,剩下15、30和80:

步骤1:从其他列值中减去最低列值。




Python 矩阵的最大值 python计算矩阵_ViewUI_06

现在,我们将浏览其余的列并进行更新:

步骤1:从其他列值中减去最低列值。




Python 矩阵的最大值 python计算矩阵_最小值_07

现在,我们将注意到每一列都包含一个零。 但是,只有第1、3和4行为零,其中第2行为0。 从此处开始,我们继续执行步骤2。现在,我们循环浏览各行,并将每行的最小值转换为零(仅当该行当前不为零时)。

步骤2:确定不包含0值的行中的最低行值。




Python 矩阵的最大值 python计算矩阵_python_08

现在,重复上一步,我们将从行中的其余值中减去该值:

步骤2:从该行的其他值中减去最低的行值。




Python 矩阵的最大值 python计算矩阵_Python 矩阵的最大值_09

步骤3:确定最低的工作并将其分配给承包商。

完成第2步后,我们可以看到每一行和每一列都为零,这使我们面临向每个承包商分配适当工作的挑战。 从这里,我们将只选择零的行或列值。 在第4行中,我们可以为绘画或地板选择Susan。 我们可以选择迭戈或苏珊作为地板。 如果我们在不使用Python或其他程序的情况下手动分配适当的列和行值,则可能会首先选择没有其他选择的值。 在这里,第2列和第4列仅给我们一个选择,因此我们可以首先选择那些。 在选择Susan地板或绘画时,我们可以看到,如果选择Susan地板,则消除了第4行,这使第1列没有替代零。因此,唯一可能的解决方案是迭戈针对地板和Susan。绘画,允许我们为每一行和每一列选择一个零。

现在,这原本是我们已经决定的,只有4x4矩阵,这并不困难。 但是,想象一下我们的矩阵是否更大。 试图以这种方式分配工作,以最小化时间和费用,将是非常困难的。 这种方法可以使计算更加容易。

现在,让我们看一下如何创建一个程序可以为我们解决这个问题。 我的目标不是简单地编写程序来解决这个确切的问题,而是编写可以解决任何大小矩阵的问题的代码,从而使我可以将代码重复用于多个应用程序。 您可以看到如何在各种设置中非常有用。

首先,我将矩阵放入一个数组中,因为使用起来会更容易一些。 然后,如果我需要重复使用代码,则只需从阵列中刷出一个新的代码即可。


arr = [100, 130, 115, 55, 150, 75, 35, 110, 85, 50, 120, 120, 70, 150, 25, 90]


现在,对下一步要做什么有一个清晰的认识是个好主意。 对我来说,跟踪几件事很有意义。 我有这个数字列表,但是请记住匈牙利方法的工作原理,我们想了解每个数字的几件事,例如它的当前值是什么,它的修改值是什么,数字在哪一行以及哪一列号码开了。 我可能还想知道该值出现在列表中的索引值。 对我来说,将数字列表转换为python字典列表很有意义。 python字典看起来很像JavaScript对象。 这基本上是我想做的:




Python 矩阵的最大值 python计算矩阵_最小值_10

这样,将每个值转换成字典后,当我循环遍历每个数字时,便可以从每个数字中获取更多信息。 拥有修改后的原始值也有帮助,因为修改后的值将帮助我们最终分配要使用的值,而原始值是实际价格或成本,我们最终需要参考这些值。

首先,我将设置一些变量,这些变量将帮助我将数字列表转换为字典列表:



arr2 = []
numberOfRows = 4
numberOfColumns = 4
column = 0



2号

—当我遍历原始列表arr ,我会将修改后的字典推入到新列表arr2字典中。

行数和列数

这些变量的妙处在于,它们将帮助我们跟踪矩阵中的位置。 同样,它将帮助我们保持代码的可重用性。 将来,如果我们更改此矩阵或开始一个新的矩阵,则只需更新列表以及行和列的数量,Python就会重新计算其余的矩阵。 它使我们几乎没有什么可以改变的。

此变量将为我们提供遍历列表的起点。 我们可以随时增加它,并相应地更新字典。

现在,我们将开始for循环,并为其指定条件:



for idx, val in enumerate(arr):
    row = len(arr2)/numberOfRows+1
    column = column + 1
    if column > numberOfColumns:
        column = 1



对于idx,枚举(arr)中的val:

Python中的枚举方法将使我们能够看到每个列表项中的值和索引号。 这将帮助我们获取要添加到对象中的index value以及original value

行= len(arr2)/ numberOfRows + 1

这就是我们跟踪添加到当前字典的行值的方式。 例如,如果我们在for循环的第一项上,则尚未向arr2添加任何内容。 因此arr2的长度将为0。在此练习中,我们知道numberOfRows为4,因此0/4 + 1 =1。因此,我们的行将为1。但是,如果我们位于最后一项,则ve已经为arr2增加了很多。 该点处arr2的长度为15。因此15/4 = 3 +1 =4。则行将为4。

列=列+ 1

在这里,由于我们的原始值为0,所以由于没有第0列,所以我们只增加了1。在每个列表项之后,我们的列将增加1。

如果column> numberOfColumns:
列= 1

这里的条件有助于我们跟踪列。 例如,在这种情况下,我们不能连续增加列,因为最大列数是4。 因此,由于我们将列增加一,所以如果在循环中每个项目的开头,如果当前列数大于4,它将重置为1,然后再次开始递增,直到再次达到5 ,并将重置。

现在,我们将创建字典:



idx = {
        "row": row,
        "column": column,
        "index": idx,
        "original_value": val,
        "modified_value": val,
    }
    arr2.append(idx)



在这里,我们只是使用已经设置的值,并创建键值对以允许我们以后访问这些值。 这是整个代码块的外观:



for idx, val in enumerate(arr):
    row = len(arr2)/numberOfRows+1
    column = column + 1
    if column > numberOfColumns:
        column = 1
    idx = {
        "row": row,
        "column": column,
        "index": idx,
        "original_value": val,
        "modified_value": val,
    }
    arr2.append(idx)



现在,我将通过列表中的原始值键对列表进行排序。 稍后,我将要访问每一列和每一行中的最低值,如果按最低的原始值对它们进行排序,这会容易得多。 我们将执行以下操作:


newlist = sorted(arr2, key=lambda k: k['original_value'])

我现在使用的变量是newlist 。 从现在开始,我将不需要arrarr2 ,但是我将只与该列表newlist交互。 这是我的输出,以供参考:



{'column': 3, 'index': 14, 'original_value': 25, 'modified_value': 25, 'row': 4}
{'column': 3, 'index': 6, 'original_value': 35, 'modified_value': 35, 'row': 2}
{'column': 2, 'index': 9, 'original_value': 50, 'modified_value': 50, 'row': 3}
{'column': 4, 'index': 3, 'original_value': 55, 'modified_value': 55, 'row': 1}
{'column': 1, 'index': 12, 'original_value': 70, 'modified_value': 70, 'row': 4}
{'column': 2, 'index': 5, 'original_value': 75, 'modified_value': 75, 'row': 2}
{'column': 1, 'index': 8, 'original_value': 85, 'modified_value': 85, 'row': 3}
{'column': 4, 'index': 15, 'original_value': 90, 'modified_value': 90, 'row': 4}
{'column': 1, 'index': 0, 'original_value': 100, 'modified_value': 100, 'row': 1}
{'column': 4, 'index': 7, 'original_value': 110, 'modified_value': 110, 'row': 2}
{'column': 3, 'index': 2, 'original_value': 115, 'modified_value': 115, 'row': 1}
{'column': 3, 'index': 10, 'original_value': 120, 'modified_value': 120, 'row': 3}
{'column': 4, 'index': 11, 'original_value': 120, 'modified_value': 120, 'row': 3}
{'column': 2, 'index': 1, 'original_value': 130, 'modified_value': 130, 'row': 1}
{'column': 1, 'index': 4, 'original_value': 150, 'modified_value': 150, 'row': 2}
{'column': 2, 'index': 13, 'original_value': 150, 'modified_value': 150, 'row': 4}



[Finished in 0.089s]



这是一个好主意,因为我们一直在打印每个列表的结果,以确保我们拥有期望的数据。

接下来,我将创建空白列表:



columnsTested = []
columnAndValue = []



我的想法是在新列表中循环。 由于它是按原始值组织的,因此我将每列中的最低值附加到columnAndValue ,然后仅将列值推入columnsTested 。 这样,我可以创建一个条件,该条件将检查x列是否已在columnsTested 。 如果是这样,我将跳过它。



for i in newlist:
    testObj = {
        "column": i['column'],
        "minVal": i['original_value']
    }



要开始我的名单,我创建的列和对象original value ,后来我将测试对我的这个对象newlist名单。 我可以说,在这一点上,如果在此列testObj我的列匹配newlist项目,我会减去minValtestObj从newlist修改后的值。 只是让您知道我对此的计划。

接下来,我将添加条件:



if i['column'] not in columnsTested:
        columnAndValue.append(testObj)
        columnsTested.append(i['column'])



现在, newlist的前6或7个项目可能在不同的列中,但是由于它是从最低值开始组织的,因此它可能会抓住该项目和索引3(位于列2中)。然后索引4的值也可能位于第2列,但不会获得第二个值,因为columnsTested已经存在第2列的值。 并且它附加到columnAndValue的第一个值小于第二个。

这是这段代码的外观:



columnsTested = []
columnAndValue = []
for i in newlist:
    testObj = {
        "column": i['column'],
        "minVal": i['original_value']
    }
    if i['column'] not in columnsTested:
        columnAndValue.append(testObj)
        columnsTested.append(i['column'])



现在,我将执行一个嵌套的for循环,以针对columnAndValue中的字典测试newlist中的字典。 如果每个列中的列都匹配,那么我将从newList中的ModifyedValue的columnAndValue减去minVal。 在这一点上,modifiedValue和originalValue是相同的,但这将使我们在两个值上想要有所不同。



for i in newlist:
    for j in columnAndValue:
        if i['column'] == j['column']:
            i['modified_value'] = i['modified_value'] - j['minVal']



很简单吧? 同样,检查是个好主意,并通过打印newlist的内容来确保我们拥有期望的数据。 我们的输出可能看起来像这样:



{'column': 3, 'index': 14, 'original_value': 25, 'modified_value': 0, 'row': 4}
{'column': 3, 'index': 6, 'original_value': 35, 'modified_value': 10, 'row': 2}
{'column': 2, 'index': 9, 'original_value': 50, 'modified_value': 0, 'row': 3}
{'column': 4, 'index': 3, 'original_value': 55, 'modified_value': 0, 'row': 1}
{'column': 1, 'index': 12, 'original_value': 70, 'modified_value': 0, 'row': 4}
{'column': 2, 'index': 5, 'original_value': 75, 'modified_value': 25, 'row': 2}
{'column': 1, 'index': 8, 'original_value': 85, 'modified_value': 15, 'row': 3}
{'column': 4, 'index': 15, 'original_value': 90, 'modified_value': 35, 'row': 4}
{'column': 1, 'index': 0, 'original_value': 100, 'modified_value': 30, 'row': 1}
{'column': 4, 'index': 7, 'original_value': 110, 'modified_value': 55, 'row': 2}
{'column': 3, 'index': 2, 'original_value': 115, 'modified_value': 90, 'row': 1}
{'column': 3, 'index': 10, 'original_value': 120, 'modified_value': 95, 'row': 3}
{'column': 4, 'index': 11, 'original_value': 120, 'modified_value': 65, 'row': 3}
{'column': 2, 'index': 1, 'original_value': 130, 'modified_value': 80, 'row': 1}
{'column': 1, 'index': 4, 'original_value': 150, 'modified_value': 80, 'row': 2}
{'column': 2, 'index': 13, 'original_value': 150, 'modified_value': 100, 'row': 4}



[Finished in 0.107s]



现在,我们将重复最后两个步骤,但是将行而不是列作为目标,但是该代码的所有构造块将完全相同:



rowsTested = []
rowAndValue = []
for i in newlist:
    testObj = {
        "row": i["row"],
        "minVal": i["modified_value"],
        "modified": i["modified_value"]
    }
    if i['row'] not in rowsTested:
        rowAndValue.append(testObj)
        rowsTested.append(i['row'])



for i in newlist:
    for j in rowAndValue:
        if i['row'] == j['row'] and j['modified'] > 0:
            i['modified_value'] = i['modified_value'] - j['minVal']



瞧! 现在,如果我们打印新列表,我们可以看到带有0的四个值在列表的顶部,并且我们可以轻松地选择那些不在重复的行或列中出现的值。 我们的输出应如下所示:



{'column': 3, 'index': 14, 'original_value': 25, 'modified_value': 0, 'row': 4}
{'column': 3, 'index': 6, 'original_value': 35, 'modified_value': 0, 'row': 2}
{'column': 2, 'index': 9, 'original_value': 50, 'modified_value': 0, 'row': 3}
{'column': 4, 'index': 3, 'original_value': 55, 'modified_value': 0, 'row': 1}
{'column': 1, 'index': 12, 'original_value': 70, 'modified_value': 0, 'row': 4}
{'column': 2, 'index': 5, 'original_value': 75, 'modified_value': 15, 'row': 2}
{'column': 1, 'index': 8, 'original_value': 85, 'modified_value': 15, 'row': 3}
{'column': 4, 'index': 15, 'original_value': 90, 'modified_value': 35, 'row': 4}
{'column': 1, 'index': 0, 'original_value': 100, 'modified_value': 30, 'row': 1}
{'column': 4, 'index': 7, 'original_value': 110, 'modified_value': 45, 'row': 2}
{'column': 3, 'index': 2, 'original_value': 115, 'modified_value': 90, 'row': 1}
{'column': 3, 'index': 10, 'original_value': 120, 'modified_value': 95, 'row': 3}
{'column': 4, 'index': 11, 'original_value': 120, 'modified_value': 65, 'row': 3}
{'column': 2, 'index': 1, 'original_value': 130, 'modified_value': 80, 'row': 1}
{'column': 1, 'index': 4, 'original_value': 150, 'modified_value': 70, 'row': 2}
{'column': 2, 'index': 13, 'original_value': 150, 'modified_value': 100, 'row': 4}



[Finished in 0.082s]



很棒的事情是,尽管这需要花费一些时间来建立,但我们现在可以评估任何所需的矩阵以解决类似问题。