Pemrograman dinamis dengan sejumlah besar masalah. Jadi saya mencoba menyelesaikan masalah ini dari Interview Street:
Grid Walking (Nilai 50 poin)
Anda berada di grid dimensi pada posisi . Dimensi grid adalah ). Dalam satu langkah, Anda dapat berjalan satu langkah di depan atau di belakang di salah satu dari dimensi (Jadi selalu ada gerakan yang mungkin berbeda). Berapa banyak cara yang bisa Anda ambil langkah-langkah sedemikian rupa sehingga Anda tidak meninggalkan grid di titik mana pun? Anda meninggalkan kotak jika untuk , baik atau .
Percobaan pertama saya adalah solusi rekursif memoised ini:
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
Kejutan besar: gagal untuk sejumlah besar langkah dan / atau dimensi karena kurangnya memori.
Jadi langkah selanjutnya adalah meningkatkan solusi saya dengan menggunakan pemrograman dinamis. Tetapi sebelum memulai, saya melihat masalah besar dengan pendekatan tersebut. Argumennya starting_point
adalah -tuple, di mana sebesar . Jadi sebenarnya, fungsinya bisa number_of_ways(steps, x1, x2, x3, ... x10)
dengan .
Masalah pemrograman dinamis yang saya lihat di buku pelajaran hampir semuanya memiliki variabel twp, sehingga hanya diperlukan matriks dua dimensi. Dalam hal ini, matriks sepuluh dimensi akan diperlukan. Jadi sel total.
Dengan matriks 2-D dalam pemrograman dinamis, biasanya hanya baris perhitungan sebelumnya yang diperlukan untuk perhitungan selanjutnya, sehingga mengurangi kompleksitas spasial dari ke min ( m , n ) . Saya tidak yakin bagaimana saya akan melakukan hal yang sama dalam kasus ini. Memvisualisasikan tabel tidak layak, jadi jawabannya harus datang langsung dari rekursi di atas.
MEMPERBARUI
Menggunakan saran Peter Shor, dan membuat beberapa koreksi kecil, terutama kebutuhan untuk melacak posisi dalam fungsi , dan bukannya hanya membelah dimensi menjadi dua set A dan B, melakukan pemisahan secara rekursif, secara efektif menggunakan metode divide-and-conquer, hingga base case tercapai di mana hanya satu dimensi berada di set.
Saya datang dengan implementasi berikut, yang lulus semua tes di bawah waktu eksekusi maksimum:
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
sumber
mem[]
kamus. Dan terima kasih telah membersihkan jawaban saya. Tidak terlalu terbiasa dengan LaTeX tetapi akan berusaha di waktu berikutnya.Jawaban:
Anda dapat melakukan yang lebih baik lagi. Secara rekursif membagi dimensi menjadi dua himpunan bagian, dan , dan menghitung berapa banyak berjalan ada hanya menggunakan dimensi di bagian , dan hanya orang-orang di . Sebut angka-angka ini dan , masing-masing. Anda mendapatkan jumlah total jalan kaki denganA B A B WA(t) WB(t)
sumber
Mari kita ekstrak formula untuk dari kode Anda (untuk sel dalam, yang mengabaikan kasus perbatasan):now(s,x1,…,xn)
Berikut ini beberapa ide.
Itu harus cukup untuk menjaga penggunaan memori cukup rendah.
sumber