通过Transition矩阵以非逐步方式进行优化

时间:2014-04-26 10:07:11

标签: python algorithm probability

考虑到一些有限资源的分配(例如在这种情况下为4),我做了某种成功概率增加的转换矩阵:

            inc1     inc2      inc3      inc4  

option1    0.0000   0.0000    0.3021    0.1541 
option2    0.1000   0.0100    0.0010    0.0001 
option3    0.2000   0.0000    0.0000    0.0000

此时,我以逐步的方式考虑分配。也就是说,每增加+1,我只需检查哪个选项可以最大化支付。通常,我添加到一个选项越多,增加量就越小(从而打开其他选项的窗口)。

然而,我注意到它有时会卡住:如果只是我愿意允许0增加一段时间,我可以获得惊人的增长。

我怎样才能最大限度地提高增幅,不仅仅是以逐步的方式进行,而是将其视为一个整体?

请注意,逐步将如下所示:

     option3 -> option2 -> option2 -> option2 = 0.311

而这里的最佳解决方案是:

     option3 -> option1 -> option1 -> option1 = 0.5021

另请注意,这是一个简单的案例,有更多选项和不同的支出。因此,仅仅考虑这个具体问题并且没有概括的答案是无用的。

您解决此问题的方法是什么?



注意:我认为这将是一个问题,最多20个选项,分配的总和可能是25.我正在寻找一个有效的实现,或只是一些一般的技巧,不必考虑每一个组合。

注意2:我用Python标记它,因为我会在那里实现它,尽管我估计我只是在寻找CS建议。

2 个答案:

答案 0 :(得分:1)

动态编程将快速而简单。对于i从0到m的行数,确定前i行如何最好地分配k步(从0到n)。要从i行转到i + 1,我们尝试在前i行和行i + 1之间的所有可能的步骤划分(j是分配给i + 1的数字)并且采取最佳行为。

Python示例:

def optimize(matrix, steps):
    best = {j: (0, ()) for j in range(steps + 1)}
    for i, row in enumerate(matrix):
        bestprime = best.copy()
        p = 0
        for j, pj in enumerate(row):
            if pj == 0: continue
            p += pj
            for k in range(j + 1, steps + 1):
                bestprime[k] = max(bestprime[k],
                                   (best[k - j - 1][0] + p,
                                    best[k - j - 1][1] + (i + 1,) * (j + 1)))
        best = bestprime
    return bestprime[steps]

>>> optimize([[0  , 0   , 0.3021, 0.1541],
...           [0.1, 0.01, 0.001 , 0.0001],
...           [0.2, 0   , 0     , 0     ]], 4)
(0.5021, (1, 1, 1, 3))

答案 1 :(得分:1)

所以,我想出了一个不同的答案。不确定它是如何扩展的(编辑:非常好,显然。它在10,000s中完成了10,000x10,000矩阵,100步),但是,它很有趣。 :)

import copy
import random
import timingdecorator as timeit

test1 = [[0,0,.3021,.1541],
        [.1,.01,.001,.0001],
        [.2,0,0,0]]

test2 = [[.2,0,1.9,.4],
        [.6,0,0,0],
        [.2,0,.1,0]]


test3 = [ [ random.random() for x in xrange(10) ] for i in xrange(10) ]

def findmaxspot(matrix):
    mx = -1
    spot = (0,0)
    for rindex,row in enumerate(matrix):
        for vindex,val in enumerate(row):
            if val>mx:   # hmm... ties... issue?
                mx = val
                spot = (rindex,vindex+1)
    return (mx,spot)

def efficiency(row):
    return [ float(sum(row[:i+1]))/(i+1) for i,val in enumerate(row) ]

@timeit.timeit
def optimize(tm,steps,checksteps=False):
    r = 0
    matrix = [ row[:steps] for row in tm ]
    choices = []
    m = [ efficiency(row) for row in matrix ]
    # print m
    while steps:
        if checksteps:
            if not any(m):
                return (r,choices)
        choice = findmaxspot(m)
        if choice[0]==0:
            return (r,choices)
        steps -= choice[1][1]
        r += sum(matrix[choice[1][0]][:choice[1][1]])
        for x in xrange(choice[1][1]):
            choices.append(choice[1][0])
        for index, row in enumerate(matrix):
            if index==choice[1][0]:
                matrix[index] = matrix[index][choice[1][1]:]
                m[index] = efficiency(matrix[index])
            else:
                matrix[index] = matrix[index][:steps]
                m[index] = m[index][:steps]
        # print (choice,m)
    return (r,choices)

因此,它首先计算一个具有每步平均回报的矩阵。显然,第三个选项在第一步中获胜。然后,它删除采取的选项(我认为这是一个有效的约束,你不能采取第四个选项4次)并修剪所有无法到达的点。然后它重建效率矩阵,发现下一个是第一个选项,所以我们拿走那些!

认为总能找到最佳解决方案,但我不确定。如果你找到反案,请告诉我。如果您愿意将它发送给我,我真的有兴趣在完整数据集上测试它。 :)

EDIT3:应该注意的是,返回的移动顺序也是最有效的顺序。也就是说,如果在任何时候中断,我的解决方案仍然是最佳的。如果我计划投资9步但在6点被打断,我将只投资6步的最佳方式。然而,大卫可能不是最理想的,因为他的数字排序,而不是优先顺序。

编辑:我意识到我实际上只需要重新计算从一开始就修剪的行的效率,所以我们只需要一次重新计算一行。

EDIT2:同样,通过在开始时修剪大幅矩阵的性能大幅提升。如果你测试我和大卫的解决方案,那么我的10k x 10k矩阵需要6.4秒才能完成100步,而他需要32.6秒。