院卒新人サラリーマンのメモ代わり

備忘としてのメモを記載

数学パズル Q5

# 入力:数値
# 出力:組み合わせの数
def ryogae(tar)
  cnt = 0
  (0..15).each do |zyu|
    (0..15).each do |gozyu|
      (0..15).each do |hyaku|
        (0..15).each do |gohyaku|
          next if zyu + gozyu + hyaku + gohyaku > 15
          val = 10 * zyu + 50 * gozyu + 100 * hyaku + 500 * gohyaku
          cnt += 1 if val == tar
        end
      end
    end
  end
  cnt
end

puts ryogae(1000)

配列に硬貨を入れて、重複組合せでチェックするのが一番良さそう。
重複組合せをぱっとは作れないので後回し。
現在の硬貨と次に追加する硬貨で再帰でも作れそう。

追記 再帰バージョン

def ryogae(tar, accCoins = [])
  return 0 if accCoins.sum > tar || accCoins.length > 15
  # 重複があるから弾く、もう少し良いやり方を考えたい
  return 0 if accCoins != accCoins.sort
  return 1 if accCoins.sum == tar

  coins = [10, 50, 100, 500]
  coins.reduce(0) do |acc, cur|
    acc + ryogae(tar, [*accCoins, cur])
  end
end


追記 重複組合せ
上のコード書いたらなんか重複組合せが簡単にできそうだったから書いてみた
配列が深くなってしまったとこがびみょい

# 重複組合せ
def kumi(num, arr, accKumi = [])
  return if accKumi.count > num
  return if accKumi != accKumi.sort
  return accKumi if accKumi.count == num

  arr.reduce([]) do |acc, cur|
    val = kumi(num, arr, [*accKumi, cur])
    val.nil? ? acc : acc.push(val)
  end
end

p kumi(3, [1, 2, 3, 4])

追記
読み返してみたけど、これ何やってんだろう
重複組合せでもない