Ruby - khoảng 700 golf. Tôi đã bắt đầu một phiên bản chơi gôn, với các tên ký tự đơn cho các biến và phương thức, nhưng sau một thời gian tôi đã quan tâm đến thuật toán hơn so với golf, vì vậy đã ngừng cố gắng tối ưu hóa độ dài mã. Tôi cũng không lo lắng về việc nhận được chuỗi đầu vào. Nỗ lực của tôi là dưới đây.
Để giúp bạn hiểu cách thức hoạt động của nó, tôi đã bao gồm các nhận xét cho thấy cách thức một chuỗi cụ thể (u = "2 1 4 3 0 3 4 4 3 5 0 3") được thao tác. Tôi liệt kê các kết hợp của "đá trong dòng" có sẵn để nhảy vào. Chúng được biểu diễn bằng một chuỗi nhị phân. Tôi đưa ra ví dụ 0b0101101010 trong các bình luận và chỉ ra cách sử dụng nó. Số 1 tương ứng với vị trí của các tảng đá có sẵn cho chuyến đi ban đầu; 0 giây cho chuyến trở về. Đối với mỗi phân bổ như vậy, tôi sử dụng lập trình động để xác định số bước nhảy tối thiểu cần thiết cho mỗi hướng. Tôi cũng thực hiện một vài tối ưu hóa đơn giản để loại bỏ một số kết hợp sớm.
Tôi đã chạy nó với các chuỗi được đưa ra trong các câu trả lời khác và nhận được kết quả tương tự. Dưới đây là một số kết quả khác tôi thu được:
"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
Tôi sẽ quan tâm đến việc liệu những người khác có nhận được kết quả tương tự cho các chuỗi này hay không. Hiệu suất là hợp lý tốt. Ví dụ: mất ít hơn một phút để có được giải pháp cho chuỗi này:
"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"
Các mã sau.
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.
- không phải1 0
là một ví dụ?