2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Ruby ボーナスドリンク問題 解いてみた(解答例あり)

Last updated at Posted at 2020-05-30

はじめに

『プロを目指す人のためのRuby入門』通称チェリー本を学習後のプログラミング初心者です。
インプットしたものを手を動かして実践してみたいなと思ったら、作者の記事を見つけました。
「アウトプットのネタに困ったらこれ!?Ruby初心者向けのプログラミング問題を集めてみた(全10問)」

この4つ目の問題を解いてみました。

他の問題はこちら
一問目:カレンダー作成問題(たのしいRuby 練習問題)
二問目:カラオケマシン作成問題
三問目:ビンゴカード作成問題
四問目:ボーナスドリンク問題
五問目:電話帳作成問題

問題

詳細はここから

ある駄菓子屋で飲み物を買うと、空き瓶3本で新しい飲み物を1本プレゼントしてくれる。
最初に購入した飲み物の本数から、トータルで飲める本数を算出するプログラムを作成せよ。
また、最初に100本購入した場合、トータルで何本飲めるか。

備考
この問題は小学校3年生の算数の問題をベースとしている。

| 購入した本数 | 飲める本数 |
|--:|--:|
| 0 | 0 |
| 1 | 1 |
| 3 | 4 |
| 11 | 16 |
| 100 | (プログラムで算出する) |

解答例

こんな感じになりました

class BonusDrink
  def self.total_count_for(amount)
    if amount.zero?
      0
    elsif amount.odd?
      3 * amount / 2
    elsif amount.even?
      3 * (amount - 1) / 2 + 1
    end
  end
end

テストコードはこちらです。

require_relative '../Bonus_drink/drink'

RSpec.describe BonusDrink do
  it "total_count_for" do
    expect(BonusDrink.total_count_for(0)).to eq 0
    expect(BonusDrink.total_count_for(1)).to eq 1
    expect(BonusDrink.total_count_for(3)).to eq 4
    expect(BonusDrink.total_count_for(11)).to eq 16
  end
end

解説

プログラムとして成立してるとは思うのですが、プログラミングの問題の趣旨としてこの解き方で良かったのかなという感じは若干あります。
(ほとんど紙とペンを動かして算数的に解きました。)

まず

問題にもある通り、「空き瓶3本と新たな1本を交換」してもらえます。
交換して受け取った新たな瓶1本も交換対象になるのがこの問題の肝です。

ですので

購入した本数:3 新たに交換した本数:1  合計で飲んだ本数:4

となりますが、受け取った瓶を追加して3本に達するとさらにもう一本交換できるのです。
例えば、

購入した本数:5  新たに交換した本数:1  さらに追加で交換した本:1 合計で飲んだ本数:7

ということになります。
したがって購入した本数が増えれば増えるほど、追加の交換が何度も繰り返されます。

これをプログラミングで表現して合計の瓶の本数・交換済みの本数などを繰り返し代入して最大の合計本数に近づけていく問題なのかと思ったのですが、思い付かず、諦めました。
何か解答例あればコメントで教えていただけますと幸いです。

ここから解説

ではどう解いたかというと、購入した本数と飲める本数をとりあえず少し書き出してみました。

購入した本数 飲める本数
0 0
1 1
2 2
3 4
4 5
5 7
6 8
7 10
8 11
9 13
10 14
11 16

そうすると、***「購入した本数nが奇数の時、(n * 3)の値はnの時の飲める本数と(n+1)の時の飲める本数の合計と一致する」***ということがわかりました。
ちなみに0の時は成立しません。
(他にも色々法則性はありますが、今回はこの方程式を使います。)
具体的には、

購入した本数 飲める本数
5 7
6 8
5 * 3 = 15
7 + 8 = 15

なりますね!
つまり***「nを3倍にしたものを2で割ると飲める本数を求められる」***ことがわかりました。
これをプログラミングに直すと、

# 奇数の時
3 * amount / 2
# 偶数の時は1つ前の奇数から求めました
3 * (amount - 1) / 2 + 1

以上の内容をまとめたものが、上記の解答例です。

さいごに

こういう法則が成り立つな、というのは分かったのですが、**「なんでこうなるのか」**がいまいちわからないです。
わかりやすく説明していただける方いましたらお恥ずかしながらご教授お願いしたいです。

よろしくお願いします!

2
0
4

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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?