(備忘録)AtCoderをやって 5 (Otoshidama)

問題

日本でよく使われる紙幣は、10000 円札、5000 円札、1000 円札です。以下、「お札」とはこれらのみを指します。

青橋くんが言うには、彼が祖父から受け取ったお年玉袋にはお札が N 枚入っていて、合計で Y 円だったそうですが、嘘かもしれません。このような状況がありうるか判定し、ありうる場合はお年玉袋の中身の候補を一つ見つけてください。なお、彼の祖父は十分裕福であり、お年玉袋は十分大きかったものとします。

制約

1≤N≤2000

1000≤Y≤2×10 7

N は整数である。

Y は 1000 の倍数である。

自分の回答(他の方回答参考)

0..nを用いてeachを使うのかなというのは思いついていましたが、 入れ子させたeachの方でn-aのようにする発想は思いつきませんでした。 あと一万円、五千円、千円の枚数をeach文の中でputsさせるような実装を考えていましたが、 それぞれの初期値を-1(該当しなかった場合の返り値)に設定しておき、each文が終わった後でputsさせる方が 分かりやすかったですね。

n, y = gets.split.map(&:to_i)
ten_thousand_yen = -1
five_thousand_yen = -1
thousands_of_yen = -1
(0..n).each{ |a|
  (0..n - a).each{ |b|
     if y == (10000*a + 5000*b + 1000*(n-a-b))  
       ten_thousand_yen = a
       five_thousand_yen = b
       thousands_of_yen = (n-a-b)
     end
  }
}
puts "#{ten_thousand_yen} #{five_thousand_yen} #{thousands_of_yen}"

その他回答

putsをeachの中で使っているパターン。foundを初期値falseにして置いてマッチするパターンが見つかった時にfoundをtrueにしてcatch throwを使って全てのループを脱出するわけですね。(最初breakで良くね?と思ったけどbreakだと一番内側の繰り返ししか脱出できないからだとわかった)

N,Y = gets.split.map(&:to_i)

found = false
catch(:break_loop) do
  (0..N).each do |a|
    (0..(N-a)).each do |b|
      c = N-a-b
      if a*10000 + b*5000 + c*1000 == Y
        puts "#{a} #{b} #{c}"
        found = true
        throw :break_loop
      end
    end
  end
end

puts "-1 -1 -1" unless found