非決定計算
30分プログラム、その43。id:Gemmaさん出題によるラグランジェの4平方定理。id:zyxwv:20070531に対抗してみる。
ある自然数nが与えられた場合、
という等式を満す非負の整数a,b,c,dをすべて求める問題。(微妙にオリジナルと変えました)
まず、callccで非決定計算を行なえるようにしてから、その上で問題を解いている。
class Amb def initialize @paths = [] end def choice(*choices) if choices.empty? self.fail else callcc do|cc| @paths.push(*choices.map do|choice| lambda{ cc.call choice } end) self.fail end end end def fail if @paths.empty? then throw :last else cc = @paths.pop cc.call end end end def lagrange(amb,n) seed = (0..Math.sqrt(n).floor).map{|x| x*x} a = amb.choice(*seed) b = amb.choice(*seed.select{|x| x <= a}) c = amb.choice(*seed.select{|x| x <= b}) d = amb.choice(*seed.select{|x| x <= c}) if a + b + c + d == n then [a,b,c,d] else amb.fail end end def all_lagrange(x) amb = Amb.new result = [] catch(:last){ result.push lagrange(amb,x) loop { amb.fail } } result end