Ruby - ประมาณ 700 golfed ฉันเริ่มเวอร์ชัน golfed ด้วยชื่อตัวอักษรเดียวสำหรับตัวแปรและวิธีการ แต่หลังจากชั่วครู่ฉันก็สนใจอัลกอริธึมมากกว่ากอล์ฟดังนั้นหยุดพยายามปรับความยาวโค้ดให้เหมาะสม ฉันไม่กังวลเกี่ยวกับการรับสายอินพุต ความพยายามของฉันอยู่ด้านล่าง
เพื่อช่วยให้คุณเข้าใจว่ามันทำงานอย่างไรฉันได้รวมความคิดเห็นที่แสดงว่ามีการจัดการสตริงอย่างไร (u = "2 1 4 3 0 3 4 4 3 5 0 3 3") ฉันระบุการรวมของ "หินในกระแส" ที่มีให้เพื่อกระโดดต่อไป สิ่งเหล่านี้ถูกแสดงด้วยสตริงไบนารี ฉันให้ตัวอย่าง 0b0101101010 ในความคิดเห็นและแสดงว่าจะใช้อย่างไร 1 ของสอดคล้องกับตำแหน่งของหินที่มีอยู่สำหรับการเดินทางครั้งแรก; 0 สำหรับการเดินทางกลับ สำหรับการจัดสรรแต่ละครั้งฉันใช้การเขียนโปรแกรมแบบไดนามิกเพื่อกำหนดจำนวนกระโดดน้อยที่สุดที่จำเป็นในแต่ละทิศทาง ฉันยังทำการเพิ่มประสิทธิภาพอย่างง่าย ๆ เพื่อกำจัดชุดค่าผสมบางอย่างก่อน
ฉันใช้มันด้วยสตริงที่ให้ไว้ในคำตอบอื่น ๆ และได้ผลลัพธ์เดียวกัน นี่คือผลลัพธ์อื่น ๆ ที่ฉันได้รับ:
"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
ฉันสนใจที่จะฟังว่าคนอื่น ๆ จะได้ผลลัพธ์เหมือนกันสำหรับสายเหล่านี้หรือไม่ ประสิทธิภาพเหมาะสมดี ตัวอย่างเช่นใช้เวลาน้อยกว่าหนึ่งนาทีในการรับโซลูชันสำหรับสตริงนี้:
"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 1"
รหัสดังต่อไปนี้
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.
- ไม่ใช่1 0
ตัวอย่างตัวอย่างใช่หรือไม่