作者: sugi
日時: 2002/5/14(23:23)
sugiです。

配列の順列を求めるのに良い方法がないかと考えていたのですが、
「Rubyプログラミング入門」に良いサンプルがありました。

そこで、ちょっと拡張。

任意の異なる数値の配列が与えられたとき、その中からN個の数値を取り
出して、四則演算(+、−、×、÷)で指定値になる組み合わせを探す。

--^ ticket3.rb
#! ruby

num= %w(2 3 6 8)
op = %w(+ - * /)
n  = 3
ans= 10

# 順列
def perm(n,m=n)
  if n<m
  elsif m<=0
    yield([])
  else
    perm(n-1,m-1) do |x|
      (0...m).each do |i|
	yield(x[0...i]+[n-1]+x[i..-1])
      end
    end
    perm(n-1,m) do |x|
      yield(x)
    end
  end
end

# 重複順列
def perm2(n,m=n)
  if n<m
  elsif m<=0
    yield([])
  else
    perm(n,m-1) do |x|
      (0...n).each do |i|
	yield(x+[i])
      end
    end
  end
end

if num.size<n
  puts "配列の要素数が足りません"
  exit0
end

count=1
num.collect!{|e| e.to_f.to_s}

num_a,op_a=[],[]
perm(num.size,n){|x|
  num_a<<x.collect{|e| num[e]}}
perm2(4,n-1){|x|
  op_a<<x.collect{|e| op[e]}}
num_a.sort!
op_a.sort!

num_a.each do |num|
  op_a.each do |op|
    ex=""
    for i in 0...n
      ex +=(op[i]) ? num[i]+op[i] : num[i]
    end
    if  eval(ex)==ans
      print %Q|#{count} #{ex.gsub(/\.0/,"")}|
      puts  %Q|=#{eval(ex.gsub(/\.0/,""))}|
      count+=1
    end
  end
end
--$

実行結果
% ruby ticket3.rb
1 2*8-6=10
2 3*6-8=10
3 6*3-8=10
4 6/3+8=10
5 6+8/2=10
6 8*2-6=10
7 8/2+6=10
8 8+6/3=10

ようやく yield の使い方がちょっと分かってきました。

この言語の比較シリーズのお題って、いろいろ勉強になります。:-)

--
sugi