There is a small time fraction possible to squeeze out from Simon's
solution.
These lines, by Simon, are trying to detect if contact has been made, in
the bi-directional search:
forward.each {|n|return pathf, pathb, n if pathb[n] != ?X}
backward.each {|n|return pathf, pathb, n if pathf[n] != ?X}
If pathf and pathb are merged into one string, this check be done
without iteration. To be able to do that we must distinguish between
numbers reached by going forward and numbers reached by going backwards.
This can be done by using lower and upper case letters:
Forward character set:
?f starting number
?a add 2
?d divide
?m multiply
Backward character set:
?F target number
?S subtract 2
?D divide
?M multiply
?X unreached number
Result:
t solve(22222222,99999999).size, 58 #8
t solve(99999999,22222222).size, 61 #8
Christer 5.108 secs
Simon 6.175 secs
The code is ugly, please turn down the light:
# store operations instead.
# one common string
# use letters for operations
def solve start, target
return [start] if start == target
@MAX = 1 + 2 + 2 * [start,target].max
op = ''.ljust(@MAX, 'X')
op[start] = ?f
op[target] = ?F
@ready = nil
q1 = [start]
q2 = [target]
loop do
q1 = solve1(q1,op)
break if @ready
q2 = solve2(q2,op)
break if @ready
end
path(@ready[0],op).reverse + path(@ready[1],op)
end
def path(n,op)
case op[n]
when ?A,?a: [n] + path(n-2,op)
when ?D,?d: [n] + path(n*2,op)
when ?S,?s: [n] + path(n+2,op)
when ?M,?m: [n] + path(n/2,op)
when ?F,?f: [n]
end
end
def solve1(queue,op)
q = []
queue.each do |n|
# store1 ?m, n, n * 2 if n+n<=@MAX
result = n + n
if result <= @MAX then
if op[result]==?X then
q.push result
op[result] = ?m
else
@ready = n, result if op[result] < ?a
end
end
# store1 ?a, n, n + 2 if n+2<=@MAX
result = n + 2
if result <= @MAX then
if op[result]==?X then
q.push result
op[result] = ?a
else
@ready = n, result if op[result] < ?a
end
end
# store1 ?d, n, n / 2 if n.modulo(2) == 0
if n.modulo(2) == 0 then
result = n / 2
if op[result]==?X then
q.push result
op[result] = ?d
else
@ready = n, result if op[result] < ?a
end
end
break if @ready
end
q
end
def solve2(queue,op)
q = []
queue.each do |n|
# store2 ?M, n, n * 2 if n+n<=@MAX
result = n + n
if result <= @MAX then
if op[result]==?X then
q.push result
op[result] = ?M
else
@ready = n, result if op[result] >= ?a
end
end
# store2 ?S, n, n - 2 if n>2
result = n - 2
if result >= 1 then
if op[result]==?X then
q.push result
op[result] = ?S
else
@ready = n, result if op[result] >= ?a
end
end
# store2 ?D, n, n / 2 if n.modulo(2) == 0
if n.modulo(2) == 0 then
result = n / 2
if op[result]==?X then
q.push result
op[result] = ?D
else
@ready = n, result if op[result] >= ?a
end
end
break if @ready
end
q
end
#def store1 op, number, result
#if result.op.nil? then
#@queue.push result
#result.op = op
#else
#@ready = number, result if result.op < ?a
#end
#end
#def store2 op, number, result
#if result.op.nil? then
#@queue.push result
#result.op = op
#else
#@ready = result, number if result.op >= ?a
#end
#end
--
Posted via http://www.ruby-forum.com/.