Quantcast
Channel: 初心者タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 21089

AtCoder Beginners SelectionでRuby学習【Coins】短いコードで解答する

$
0
0

はじめに

Ruby学習の一環として「競技プログラミング(競プロ)」に挑戦します。
そのための学習の中で学んだことをアウトプットしていきます。
今回は「AtCoder Beginners Selection」の五問目(Coins)より。
https://atcoder.jp/contests/abs

問題

500円がA枚、100円がB枚、50円がC枚持っています。
これらの硬貨の中から何枚かを選び、合計金額をX円にする方法は何通りあるか。
同じ種類の硬貨同士は区別出来ません。

制約
0 ≤ A,B,C ≤ 50
A + B + C ≥ 1
50 ≤ X ≤ 20,000
A,B,Cは整数である。
Xは50の倍数である。

入力は以下の形で与えられる。

ABCX# 例222100
出力例# 上記例の場合=>2

条件を満たす選び方は以下の2通り。
500円を0枚、100円を1枚、50円を0枚
500円を0枚、100円を0枚、50円を2枚

解答

まずは僕が最初に書いたコードです。

a=gets.to_ib=gets.to_ic=gets.to_ix=gets.to_icount=0a_array=[]b_array=[]c_array=[]foriin0..adoa_array.push(500*i)endforiin0..bdob_array.push(100*i)endforiin0..cdoc_array.push(50*i)endall_array=a_array.product(b_array,c_array)all_array.eachdo|one_array|ifone_array.inject(:+)==xcount+=1endendprintcount

① 硬貨の種類ごとに、0枚からn枚まで、選べる枚数に応じた金額を持つ配列を生成する(for~do~end)。
※100円を3枚持っているなら、[0,2,4,6]の配列が生成されるように。
② 生成された3つの配列から1つずつの要素を取り出し、新たに配列を生成。これを全パターン用意(productメソッド)
③ ②で用意した配列1つ1つに対して、その要素の合計がX(を50で割ったもの)と等しくなるパターンの数を記録する (count)。

上記のような流れで解答しました。
この解答をする中で学んだメソッドを以下にまとめていきます。

for文

for変数inオブジェクトdo実行する処理end

オブジェクトに繰り返す範囲を指定します。
解答では、0から持っている硬貨の枚数まで、0枚、1枚、2枚と順に取り出し、変数に入れるイメージです。
その上でブロック内に指定する処理を繰り返す、といった具合です。
解答では、直前に生成した配列に、枚数に応じた金額を順に入れていっています。

pushメソッド

配列オブジェクト.push(要素,)

pushメソッドは、配列の末尾に指定した要素を追加します。

productメソッド

#例[1,2].product([3,4],[5,6])=>[[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]

複数の配列が持つ全要素の組み合わせを配列にして返します。

eachメソッド

配列オブジェクト.eachdo|変数|実行する処理end

配列から要素をひとつずつ取り出し、変数に代入した上で、
要素の数だけ指定した処理を実行します。

injectメソッド

配列に対して、要素の合計を算出して返します。
今回はシンボル(:+)を用いた記法を使っています。

#例array=[1,2,3]result=array.inject(:+)printresult=>6

改めて調べていて知りましたが、sumメソッドを使うともっと簡単に書けるようです。

#例array=[1,2,3]result=array.sumprintresult=>6

短いコードで解答する

ここからは今回の解答を短くしていきます。

縦に並んだ複数の整数入力を受け取る

A,B,C,x=4.times.map{gets.to_i}

timesメソッド

指定の回数処理を繰り返す場合に使います。

#例3.times{puts"Hello, World!"}=>Hello,World!=>Hello,World!=>Hello,World!

配列を生成せず、入力された整数を直接判定に使う

解答では配列を生成して、全てのパターンの金額を追加する、ということを行っていましたが、
これによって解答がえらく長いことになってしまっていました。
入力した整数をそのままeach文を使って判定に使用することでコードの長さを抑えられました。

(0..A).each{|a|(0..B).each{|b|(0..C).each{|c|x==(500*a+100*b+50*c)?count+=1:count+=0}}}

完成

A,B,C,x=4.times.map{gets.to_i}count=0(0..A).each{|a|(0..B).each{|b|(0..C).each{|c|x==(500*a+100*b+50*c)?count+=1:count+=0}}}printcount

空白を入れて32行あったコードが9行になりました。

最後に

以上、AtCoder Beginners SelectionでRuby学習【Coins】から学んだメソッド・記法をご紹介しました。
今回のように短いコードで解答する練習は常にやっていきたいです。
他の方の解答を見てみると1行で解答をされている方もいました。
そこまでいくには道のりは長いですが、その分やりがいもありますね!

もし間違いなどございましたら、ご指摘いただけると嬉しいです。


Viewing all articles
Browse latest Browse all 21089

Trending Articles