Rubino - circa 700 golf. Ho iniziato una versione golf, con nomi a carattere singolo per variabili e metodi, ma dopo un po 'mi sono interessato più all'algoritmo che al golf, quindi ho smesso di cercare di ottimizzare la lunghezza del codice. Né mi sono preoccupato di ottenere la stringa di input. Il mio sforzo è al di sotto.
Per aiutarti a capire come funziona ho incluso commenti che mostrano come viene manipolata una particolare stringa (u = "2 1 4 3 0 3 4 4 3 5 0 3"). Elenco le combinazioni di "rocce nel flusso" che sono disponibili per salire. Questi sono rappresentati con una stringa binaria. Fornisco l'esempio 0b0101101010 nei commenti e mostro come sarebbe usato. I 1 corrispondono alle posizioni delle rocce disponibili per il viaggio iniziale; gli 0 per il viaggio di ritorno. Per ciascuna di tali allocazioni, utilizzo la programmazione dinamica per determinare il numero minimo di salti richiesti in ciascuna direzione. Eseguo anche alcune semplici ottimizzazioni per eliminare alcune combinazioni all'inizio.
L'ho eseguito con le stringhe fornite in altre risposte e ottengo gli stessi risultati. Ecco alcuni altri risultati che ho ottenuto:
"2 1 4 3 0 3 4 4 3 5 0 3" # => 8
"3 4 3 5 6 4 7 4 3 1 5 6 4 3 1 4" # => 7
"2 3 2 4 5 3 6 3 2 0 4 5 3 2 0 3" # => 10
"3 4 3 0 4 3 4 4 5 3 5 3 0 4 3 3 0 3" # => 11
"2 3 2 4 5 3 6 3 2 0 4 5 3 2 0 3 4 1 6 3 8 2 0 5 2 3" # => 14
Sarei interessato a sapere se gli altri ottengono gli stessi risultati per queste stringhe. Le prestazioni sono ragionevolmente buone. Ad esempio, ci è voluto meno di un minuto per ottenere una soluzione per questa stringa:
"3 4 3 0 4 3 4 4 5 3 5 3 0 4 3 3 0 3 4 5 3 2 0 3 4 1 6 3 2 0 4 5 3 2 0 3 4 1 6 3 0 4 3 4 4 5 0 1"
Il codice segue.
I=99 # infinity - unlikely we'll attempt to solve problems with more than 48 rocks to step on
def leap!(u)
p = u.split.map(&:to_i) # p = [2,1,4,3,0,3,4,4,3,5,0,3]
s = p.shift # s=2, p = [1,4,3,0,3,4,4,3,5,0,3] # start
f = p.pop # f=3, p = [1,4,3,0,3,4,4,3,5,0] # finish
q = p.reverse # q = [0,5,3,4,4,3,0,3,4,1] # reverse order
# No path if cannot get to a non-zero rock from s or f
return -1 if t(p,s) || t(q,f)
@n=p.size # 10 rocks in the stream
r = 2**@n # 10000000000 - 11 binary digits
j = s > @n ? 0 : 2**(@n-s) # 100000000 for s = 2 (cannot leave start if combo number is smaller than j)
k=r-1 # 1111111111 - 10 binary digits
b=I # best number of hops so far (s->f + f->s), initialized to infinity
(j..k).each do |c|
# Representative combo: 0b0101101010, convert to array
c += r # 0b10 1 0 1 1 0 1 0 1 0
c = c.to_s(2).split('').map(&:to_i)
# [1,0,1,0,1,1,0,1,0,1,0]
c.shift # [0,1,0,1,1,0,1,0,1,0] s->f: rock offsets available: 1,3,4,6,8
d = c.map {|e|1-e}.reverse # [1,0,1,0,1,0,0,1,0,1] f->s: rock offsets available: 0,2,5,7,9
c = z(c,p) # [0,4,0,0,3,0,4,0,5,0] s->f: max hops by offset for combo c
d = z(d,q) # [0,0,3,0,4,0,0,3,0,1] f->s: max hops by offset for combo c
# Skip combo if cannot get from to a rock from f, or can't
# get to the end (can always get to a rock from s if s > 0).
next if [s,f,l(c),l(d)].max < @n && t(d,f)
# Compute sum of smallest number of hops from s to f and back to s,
# for combo c, and save it if it is the best solution so far.
b = [b, m([s]+c) + m([f]+d)].min
end
b < I ? b : -1 # return result
end
# t(w,n) returns true if can conclude cannot get from sourch n to destination
def t(w,n) n==0 || (w[0,n].max==0 && n < @n) end
def l(w) w.map.with_index {|e,i|i+e}.max end
def z(c,p) c.zip(p).map {|x,y| x*y} end
def m(p)
# for s->f: p = [2,0,4,0,0,3,0,4,0,5,0] - can be on rock offsets 2,5,7,9
# for f->s: p = [3,0,0,3,0,4,0,0,3,0,1] - can be on rock offsets 3,5,8,10
a=[{d: 0,i: @n+1}]
(0..@n).each do |j|
i=@n-j
v=p[i]
if v > 0
b=[I]
a.each{|h| i+v < h[:i] ? break : b << (1 + h[:d])}
m = b.min
a.unshift({d: m,i: i}) if m < I
end
end
h = a.shift
return h[:i]>0 ? I : h[:d]
end
Thus, it should be clear that one can always jump from the last position.- non è1 0un controesempio?