Lập trình động với số lượng lớn các bài toán con. Vì vậy, tôi đang cố gắng giải quyết vấn đề này từ Interview Street:
Đi bộ theo lưới (Điểm 50 điểm)
Bạn đang ở trong lưới chiều hai chiều tại vị trí . Kích thước của lưới là ). Trong một bước, bạn có thể đi trước một bước hoặc phía sau trong bất kỳ kích thước nào. (Vì vậy, luôn luôn có có thể di chuyển khác nhau). Trong bao nhiêu cách bạn có thể thực hiện các bước sao cho bạn không rời khỏi lưới tại bất kỳ điểm nào? Bạn rời khỏi lưới nếu với bất kỳ nào , hoặc .
Thử đầu tiên của tôi là giải pháp đệ quy ghi nhớ này:
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
Bất ngờ lớn: nó thất bại đối với một số lượng lớn các bước và / hoặc kích thước do thiếu bộ nhớ.
Vì vậy, bước tiếp theo là cải thiện giải pháp của tôi bằng cách sử dụng lập trình động. Nhưng trước khi bắt đầu, tôi đang thấy một vấn đề lớn với cách tiếp cận. Đối số starting_point
là một -tuple, trong đó lớn bằng . Vì vậy, trên thực tế, chức năng có thể là với .n 10 1 ≤ x i ≤ 100number_of_ways(steps, x1, x2, x3, ... x10)
Các vấn đề lập trình động mà tôi đã thấy trong sách giáo khoa hầu hết đều có biến twp, do đó chỉ cần một ma trận hai chiều. Trong trường hợp này, sẽ cần một ma trận mười chiều. Vậy tổng cộng ô.
Với ma trận 2 chiều trong lập trình động, thường chỉ cần hàng tính toán trước đó cho phép tính tiếp theo, do đó giảm độ phức tạp không gian từ xuống . Tôi không chắc làm thế nào tôi sẽ làm như vậy trong trường hợp này. Hình dung một bảng không khả thi, vì vậy câu trả lời sẽ phải đến trực tiếp từ phép đệ quy ở trên.
CẬP NHẬT
Sử dụng các đề xuất của Peter Shor và thực hiện một số chỉnh sửa nhỏ, đáng chú ý là cần theo dõi vị trí trong hàm và thay vì chỉ chia kích thước thành hai bộ A và B, thực hiện phân tách một cách đệ quy, sử dụng hiệu quả phương pháp chia và chinh phục, cho đến khi đạt được trường hợp cơ sở trong đó chỉ có một thứ nguyên trong tập hợp.
Tôi đã đưa ra cách thực hiện sau, vượt qua tất cả các thử nghiệm dưới thời gian thực hiện tối đ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[]
từ điển. Và cảm ơn bạn đã làm sạch câu trả lời của tôi. Không quá quen thuộc với LaTeX nhưng sẽ nỗ lực trong lần tới.