我想解决的问题如下:
鉴于n美元,你有无限的硬币,镍币,硬币和硬币 四分之一,计算代表n的方式的总数。
我想出了一个递归解决方案(让我们假设n是0.25美元所以输出不是一些荒谬的数字):
def changes(w, x, y, z)
if 0.01 * w + 0.05 * x + 0.1 * y + 0.25 * z > 0.25
return
elsif 0.01 * w + 0.05 * x + 0.1 * y + 0.25 * z == 0.25
@@counter += 1
puts "w: #{w} x: #{x} y: #{y} z: #{z}"
else
changes(w + 1, x, y, z)
changes(w, x + 1, y, z)
changes(w, x, y + 1, z)
changes(w, x, y, z + 1)
end
end
@@counter = 0
changes(0, 0, 0, 0)
puts @@counter
基本上这里的想法是在匹配时递增计数器,否则尝试下一个可能的面额。
但在输出中有很多重复,如:
w: 15 x: 0 y: 1 z: 0
w: 15 x: 0 y: 1 z: 0
w: 15 x: 0 y: 1 z: 0
w: 15 x: 0 y: 1 z: 0
w: 15 x: 0 y: 1 z: 0
w: 10 x: 1 y: 1 z: 0
w: 15 x: 0 y: 1 z: 0
w: 10 x: 1 y: 1 z: 0
有人可以告诉我为什么吗?在我的递归中,我不总是传递具有不同值的参数吗?为什么多次打印相同的值?
谢谢。
答案 0 :(得分:1)
仅举例说明如何获得重复
使用changes(0, 0, 0, 0)
拨打电话。
它会失败并致电:
changes(1, 0, 0, 0) # a
changes(0, 1, 0, 0) # b
changes(0, 0, 1, 0) # c
changes(0, 0, 0, 1) # d
然后 a
将失败并致电
changes(2, 0, 0, 0) # aa
changes(1, 1, 0, 0) # ab
changes(1, 0, 1, 0) # ac
changes(1, 0, 0, 1) # ad
同时,b
将失败并致电
changes(1, 1, 0, 0) # ba
changes(0, 2, 0, 0) # bb
changes(0, 1, 1, 0) # bc
changes(0, 1, 0, 1) # bd
如您所见,ab
和ba
使用相同的参数。等等ac / ca ...
答案 1 :(得分:0)
让我用一些解释重写你的代码:
@variants = []
def changes(w, x, y, z)
case 0.01 * w + 0.05 * x + 0.1 * y + 0.25 * z
when 0...0.25
changes(w + 1, x, y, z)
changes(w, x + 1, y, z)
changes(w, x, y + 1, z)
changes(w, x, y, z + 1)
when 0.25
@variants << [w,x,y,z] unless @variants.include?([w,x,y,z])
end
end
changes(0, 0, 0, 0)
puts @variants.size
@variants.each { |v| puts "w: #{v[0]} x: #{v[1]} y: #{v[2]} z: #{v[3]}" }
您添加变量的主要想法是,如果且尚未计算。重复事实来自这样一个事实,即有不同的方式来达到州[w=1,x=1]
:[0,0]⇒[0,1]⇒[1,1]
和[0,0]⇒[1,0]⇒[1,1]
(注意中间链链接。)case
在这里更明显而不是意大利面if-elsif-end
。