具有大量子问题的动态编程。因此,我正在尝试通过Interview Street解决此问题:
网格漫游(得分50分)
您位于维网格中,位置为。网格的尺寸为)。一步,您可以在维度中的任何一个维度上向前或向后走一步。(因此,总是有可能的不同动作)。您可以采用多少种方法采取步骤,以使您在任何时候都不会离开网格?如果有任何,则离开网格,或。(X 1,X 2,... ,X Ñ)(d 1,d 2,... ,d Ñ Ñ 2 Ñ 中号X 我X 我 ≤ 0 X 我 > d 我
我的第一个尝试是这个记住的递归解决方案:
def number_of_ways(steps, starting_point):
global n, dimensions, mem
#print steps, starting_point
if (steps, tuple(starting_point)) in mem:
return mem[(steps, tuple(starting_point))]
val = 0
if steps == 0:
val = 1
else:
for i in range(0, n):
tuple_copy = starting_point[:]
tuple_copy[i] += 1
if tuple_copy[i] <= dimensions[i]:
val += number_of_ways(steps - 1, tuple_copy)
tuple_copy = starting_point[:]
tuple_copy[i] -= 1
if tuple_copy[i] > 0:
val += number_of_ways(steps - 1, tuple_copy)
mem[(steps, tuple(starting_point))] = val
return val
大惊喜:由于缺少内存,它在许多步骤和/或尺寸上失败了。
因此,下一步就是使用动态编程来改进我的解决方案。但是在开始之前,我发现该方法存在一个主要问题。参数starting_point
是元组,其中等于。因此,实际上,该函数可能具有 。Ñ 10 1 ≤ X 我 ≤ 100number_of_ways(steps, x1, x2, x3, ... x10)
我在教科书中看到的动态编程问题几乎都包含twp变量,因此只需要一个二维矩阵。在这种情况下,将需要一个十维矩阵。因此总共有单元。
对于动态编程中的二维矩阵,通常仅需要前一行计算才能进行下一次计算,因此将空间复杂度从降低到。在这种情况下,我不确定该怎么做。可视化表格是不可行的,因此答案必须直接来自上面的递归。
更新
根据彼得·索尔(Peter Shor)的建议,并进行一些较小的更正,尤其是需要跟踪函数中的位置,而不是仅将维度分为两组A和B,而是使用a进行递归拆分分而治之的方法,直到达到基本情况,即集合中只有一个维。
我想出了以下实现,通过了所有测试,但未超过最大执行时间:
def ways(di, offset, steps):
global mem, dimensions
if steps in mem[di] and offset in mem[di][steps]:
return mem[di][steps][offset]
val = 0
if steps == 0:
val = 1
else:
if offset - 1 >= 1:
val += ways(di, offset - 1, steps - 1)
if offset + 1 <= dimensions[di]:
val += ways(di, offset + 1, steps - 1)
mem[di][steps][offset] = val
return val
def set_ways(left, right, steps):
# must create t1, t2, t3 .. ti for steps
global mem_set, mem, starting_point
#print left, right
#sleep(2)
if (left, right) in mem_set and steps in mem_set[(left, right)]:
return mem_set[(left, right)][steps]
if right - left == 1:
#print 'getting steps for', left, steps, starting_point[left]
#print 'got ', mem[left][steps][starting_point[left]], 'steps'
return mem[left][steps][starting_point[left]]
#return ways(left, starting_point[left], steps)
val = 0
split_point = left + (right - left) / 2
for i in xrange(steps + 1):
t1 = i
t2 = steps - i
mix_factor = fact[steps] / (fact[t1] * fact[t2])
#print "mix_factor = %d, dimension: %d - %d steps, dimension %d - %d steps" % (mix_factor, left, t1, split_point, t2)
val += mix_factor * set_ways(left, split_point, t1) * set_ways(split_point, right, t2)
mem_set[(left, right)][steps] = val
return val
import sys
from time import sleep, time
fact = {}
fact[0] = 1
start = time()
accum = 1
for k in xrange(1, 300+1):
accum *= k
fact[k] = accum
#print 'fact_time', time() - start
data = sys.stdin.readlines()
num_tests = int(data.pop(0))
for ignore in xrange(0, num_tests):
n_and_steps = data.pop(0)
n, steps = map(lambda x: int(x), n_and_steps.split())
starting_point = map(lambda x: int(x), data.pop(0).split())
dimensions = map(lambda x: int(x), data.pop(0).split())
mem = {}
for di in xrange(n):
mem[di] = {}
for i in xrange(steps + 1):
mem[di][i] = {}
ways(di, starting_point[di], i)
start = time()
#print 'mem vector is done'
mem_set = {}
for i in xrange(n + 1):
for j in xrange(n + 1):
mem_set[(i, j)] = {}
answer = set_ways(0, n, steps)
#print answer
print answer % 1000000007
#print time() - start
mem[]
字典来耗尽所有可用的系统内存。并感谢您清理我的答案。不太熟悉LaTeX,但下次会加倍努力。