【问题标题】:How to tractably solve the assignment optimisation task如何轻松解决分配优化任务
【发布时间】:2010-11-02 04:47:36
【问题描述】:

我正在编写一个脚本,该脚本从companies 获取元素并将它们与people 的元素配对。目标是优化配对,使所有配对值的总和最大化(预先计算每个单独配对的值并存储在字典ctrPairs 中)。

他们都是1:1配对的,每个公司只有一个人,每个人只属于一个公司,公司的数量等于人数。我使用了一个自上而下的方法和一个记忆表 (memDict) 以避免重新计算已经解决的区域。

我相信我可以大大提高这里发生的事情的速度,但我不确定如何。我担心的区域标有#slow?,任何建议都将不胜感激(该脚本适用于列表 n ~15 它会变得非常慢)

def getMaxCTR(companies, people):
    if(memDict.has_key((companies,people))):
        return memDict[(companies,people)] #here's where we return the memoized version if it exists
    if(not len(companies) or not len(people)):
        return 0

    maxCTR = None
    remainingCompanies = companies[1:len(companies)] #slow?

    for p in people:
        remainingPeople = list(people) #slow?
        remainingPeople.remove(p) #slow?
        ctr = ctrPairs[(companies[0],p)] + getMaxCTR(remainingCompanies,tuple(remainingPeople)) #recurse
        if(ctr > maxCTR):
            maxCTR = ctr
    memDict[(companies,people)] = maxCTR
    return maxCTR

【问题讨论】:

  • 对不起,我猜这很混乱。我认为它遵循背包类型问题的模型,因此我们的想法是提出一个解决方案,将公司的每个元素与人的元素配对,其中所有配对的总和是所有潜在组合的最大可能值(即不会有其他可以产生更高总和的配对排列)
  • @SilentGhost 停止设置实际描述问题的标题?
  • @Marcin:别再纠结于特权了,去回答一些问题吧。
  • @SilentGhost 你是什么意思,“搞乱特权”?你对我刚刚设置的标题有什么异议?

标签: python algorithm optimization dynamic-programming


【解决方案1】:

对于所有想了解学习理论的人来说,这个问题是一个很好的例子。正确的问题不是关于“在 python 中的列表和元组之间快速跳转的方法”——缓慢的原因是更深层次的。

您在这里尝试解决的问题被称为assignment problem:给定两个列表,每个列表都有 n 个元素和 n×n 个值(每对的值),如何分配它们以便总“值”最大化(或等效地,最小化)。有几种算法可以解决这个问题,例如Hungarian algorithm (Python implementation),或者您可以使用更通用的最小成本流算法来解决它,或者甚至将其转换为线性程序并使用 LP 求解器。其中大部分的运行时间为 O(n3)。

您上面的算法所做的是尝试每种可能的配对方式。 (记忆仅有助于避免重新计算子集对的答案,但您仍在查看所有子集对。)这种方法至少为 Ω(n222n支持>)。对于 n=16,n3 是 4096,n222n 是 1099511627776。当然,每种算法都有常数因子,但请参阅区别? :-) (问题中的方法仍然比天真的 O(n!) 更好,这会更糟。)使用其中一种 O(n^3) 算法,我预测它应该及时运行 up到 n=10000 左右,而不是最多 n=15。

正如 Knuth 所说,“过早的优化是万恶之源”,但延迟/过期优化也是如此:在实施之前,您应该首先仔细考虑一个合适的算法,而不是选择一个糟糕的算法,然后想知道它的哪些部分很慢。 :-) 即使在 Python 中糟糕地实现一个好的算法也会比修复所有“慢?”快几个数量级。上面的部分代码(例如,通过用 C 重写)。

【讨论】:

  • 注意:问题的原始标题是“请求帮助:python 中的列表和元组之间跳转的快速方法是什么?”,因此是该答案的第一段。
【解决方案2】:

我在这里看到两个问题:

  1. 效率:您正在为每个公司重新创建相同的 remainingPeople 子列表。最好一次性创建所有remainingPeople 和所有remainingCompanies,然后进行所有组合。

  2. memoization:您使用元组而不是列表来将它们用作dict 用于memoization 的键;但元组身份是顺序敏感的。 IOW:(1,2) != (2,1) 你最好使用sets 和frozensets:frozenset((1,2)) == frozenset((2,1))

【讨论】:

    【解决方案3】:

    这一行:

    remainingCompanies = 公司[1:len(companies)]

    可以用这一行代替:

    remainingCompanies = companies[1:]
    

    对于非常轻微的速度增加。这是我看到的唯一改进。

    【讨论】:

      【解决方案4】:

      如果您想获取元组的副本作为列表,您可以这样做 mylist = list(mytuple)

      【讨论】:

        猜你喜欢
        • 2014-08-02
        • 1970-01-01
        • 1970-01-01
        • 2011-11-10
        • 2010-10-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-28
        相关资源
        最近更新 更多