Programmazione dinamica con un gran numero di sottoproblemi. Quindi sto cercando di risolvere questo problema da Interview Street:
Grid Walking (segna 50 punti)
Ti trovi in una griglia dimensionale in posizione . Le dimensioni della griglia sono ). In un passo, puoi camminare un passo avanti o indietro in una qualsiasi delle dimensioni. (Quindi ci sono sempre possibili mosse diverse). In quanti modi puoi fare passi in modo tale da non lasciare la griglia in nessun punto? Si lascia la griglia se per qualsiasi , o o .
Il mio primo tentativo è stato questa soluzione ricorsiva memorizzata:
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
Grande sorpresa: fallisce per un gran numero di passaggi e / o dimensioni a causa della mancanza di memoria.
Quindi il prossimo passo è migliorare la mia soluzione usando la programmazione dinamica. Ma prima di iniziare, sto riscontrando un grave problema con l'approccio. L'argomento starting_point
è una -tupla, dove è grande quanto . Quindi, in effetti, la funzione potrebbe essere con .n 10 1 ≤ x i ≤ 100number_of_ways(steps, x1, x2, x3, ... x10)
I problemi di programmazione dinamica che ho visto nei libri di testo hanno quasi tutti variabili twp, quindi è necessaria solo una matrice bidimensionale. In questo caso, sarebbe necessaria una matrice tridimensionale. Quindi celle in totale.
Con le matrici 2D nella programmazione dinamica, di solito è necessaria solo la riga precedente di calcoli per il calcolo successivo, riducendo quindi la complessità spaziale da a . Non sono sicuro di come farei lo stesso in questo caso. Visualizzare una tabella non è fattibile, quindi la risposta dovrebbe provenire direttamente dalla ricorsione sopra.
AGGIORNARE
Utilizzando i suggerimenti di Peter Shor e apportando alcune correzioni minori, in particolare la necessità di tenere traccia della posizione nella funzione e piuttosto di dividere solo le dimensioni in due insiemi A e B, facendo la scissione ricorsivamente, efficacemente usando un metodo divide-and-conquer, fino a quando non viene raggiunto un caso base in cui solo una dimensione è nell'insieme.
Mi è venuta in mente la seguente implementazione, che ha superato tutti i test al di sotto del tempo massimo di esecuzione:
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[]
dizionario. E grazie per aver ripulito la mia risposta. Non familiarità con LaTeX ma farà uno sforzo la prossima volta.