LoginSignup
0
0

More than 3 years have passed since last update.

Rubyであたまの体操

Posted at

あたまの体操してますか?

  • 以下は、 プログラマ脳を鍛える数学パズルを写経したときのメモです。回答例はRubyで記述したものです。もっとRubyのメソッドを活用すればきれいに書けるZE☆などあったら、コメントください。

  • Q1〜Q3まであります。前提条件の後に問題が表示されます。回答例を見る前にコーディングしてみると、あたまの体操になります。(たぶん)

Q1.カードを裏返したい

【前提】
1〜100までの番号が書かれた100枚のカードが1から順番に並んでいます。最初、すべてのカードは裏返しの状態になっています。ある人が2番目のカードから、1枚おきにカードを裏返していきます(2,4,6...100のカードが表を向く)。次に3番めのカードから2枚お気にカードを裏返していく。(表向きのカードは裏返され、裏向きのカードは表を向く)。このようにn番目のカードからn-1枚おきにカードを裏返す操作を、どのカードの向きも変わらなくなるまで続けたとします。

【問題】
カードの向きが変わらなくなったとき、裏向きになっているカードの番号をすべて求めてください。

【回答例】

# 100枚のカードを初期化
N = 100
cards = Array.new(N, false)

# 2〜Nまで裏返す
(2..N).each do |i|
  j= i -1
  while (j < cards.size ) do
    cards[j] = !cards[j]
    j += i
  end
end

# 最後に裏向きのカードを出力する
N.times do |i|
  puts i + 1 if !cards[i]
end

【考え方】
左から順番に処理していけばOK。
表向きを「true」, 裏向きを「false」とすることで、反転を表現できる。

Q2.棒を切り分けたい

【前提】
長さn[cm]の一本の棒を、1cm単位に切り分ける。一本の棒を一度に切ることができるのは、1人だけ。例えば、切り分けられた棒が3本あるとき、同時に3人で切ることができる。
最大m人の人間がいるとき、最短で何回切り分けられるかを求めてください。

【問題】
n=100, m=8のときの回数を求めよ。

  # currentは現在の棒の数
def cutbar(m, n , current)
  # 切り終えたとき
  if current >= n then
    0
  # 切る人より、現在の棒の数が少ない時、切れる
  elsif current < m then
  # 切れたら現在の2倍になる
    1 + cutbar(m, n, current * 2)
  else
  # 切る人の数だけ増加
    1 + cutbar(m, n, current + m)
  end
end

puts cutbar(8, 100, 1)

【考え方】
一本の棒を切れるのは1人だけ。棒を切れるときの条件を整理する。
(問題を逆に読み、1cmの棒をm人で繋いで、n[cm]の棒を作ることとも読み替えられる→別解を考えてみよう!)

Q3.どうしても現金で払いたい

【前提】
バスに設置されているような、両替機を想定してください。この機械では、10円、50円、100円、500円の組み合わせで両替することができる。両替する際に、使われない硬貨があっても構いませんが、大量の小銭は持て余すので、最大で15枚となるように両替します。例えば、「50円玉、20枚」という両替はNG。

【問題】
1,000円札を入れた時の、硬貨の組み合わせは何通りになるか?

  • 回答例[強引ver.]
count = 0
(0..2).each do |y500|
  (0..10).each do |y100|
    (0..15).each do |y50|
      (0..15).each do |y10|
        if y500 + y100 + y50 + y10 <= 15 then
          if y500 * 500 + y100 * 100 + y50 * 50 + y10 * 10 == 1000 then
            count +=1
          end
        end
      end
    end
  end
end
puts count
  • 回答例[メソッド活用ver.]
coins = [10, 50, 100, 500]
count = 0
(2..15).each do |i|
  coins.repeated_combination(i).each do |coin_set|
    count +=1 if coin_set.inject(:+) == 1000
  end
end
puts count

おわりに

いかがでしたか?
今回は、ちょっとあたまの体操がしたいなという時に解いてみたいpuzzleをご紹介しました。
ぜひこの機会にあたまをやわらかくしてみてくださいね。(こちらの記事の情報は記事更新時点のものです。事前に最新のあたまの体操情報をご確認ください)

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0