如何轻松解决分配优化任务

时间:2009-06-11 16:22:49

标签: python algorithm optimization dynamic-programming

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

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

我相信我可以大大提高这里发生的事情的速度,但我不确定如何。我担心的区域标有#slow?,任何建议都会受到赞赏(该脚本适用于列表n< 15的输入,但是对于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

4 个答案:

答案 0 :(得分:20)

对于那些对使用学习理论感到疑惑的人来说,这个问题很好。正确的问题不在于“在python中列表和元组之间反弹的快速方式” - 缓慢的原因是更深层次的。

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

上述算法的作用是尝试每种可能的配对方式。 (记忆只有助于避免重新计算子集对的答案,但您仍然在查看所有子集对。)此方法至少为Ω(n 2 2 2n )。对于n = 16,n 3 为4096,n 2 2 2n 为1099511627776.当然,每种算法都有不变因素,但请参见区别? :-)(问题中的方法仍然比天真的O(n!)更好,这会更糟糕。)使用其中一个O(n ^ 3)算法,我预测它应该及时运行起来n = 10000左右,而不是n = 15。

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

答案 1 :(得分:1)

我在这里看到两个问题:

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

  2. memoization:你使用元组而不是列表将它们用作dict密钥进行记忆;但是元组标识对顺序敏感。 IOW:(1,2) != (2,1)您最好使用setfrozenset s:frozenset((1,2)) == frozenset((2,1))

答案 2 :(得分:0)

这一行:

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

可以替换为这一行:

remainingCompanies = companies[1:]

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

答案 3 :(得分:0)

如果你想获得一个元组的副本作为列表,你可以做 mylist = list(mytuple)

相关问题