考虑到一些有限资源的分配(例如在这种情况下为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建议。
答案 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秒。