■はじめに
Rubyの基礎的な問題をたくさん解くことで基本的な考え方やメソッドの使い方を定着させたい。 基本的にはAtCoderというプログラミングコンテスト(競技プログラミング)の過去問を使う。(AtCoderは難易度が分かれており、難易度の低いA問題かB問題を解いていく)
(5/23時点の方針) メソッドの切り分け方や値の受け渡しを練習するために、コード長の短さについては気にせずに書くことにする。
(2022/10/17時点の方針) しばらくはB問題を小さい番号の方からやっていく。たまにA問題もやるかも。
■問題
●出典
AtCoder Beginner Contest 031のB問題 https://atcoder.jp/contests/abc031/tasks/abc031_b
●問題文
高橋君は AtCoder 社のマスコットキャラクターである。
マスコットキャラクターとしての魅力を維持するために、高橋君は適度な運動をすることになっている。高橋君は週の運動時間が L 分以上 H 分以下でなければならない。
しかしながら、青木君は最近、高橋君が運動しているところを見ていない。高橋君の運動状況が気になった青木君は、高橋君の過去 N 週間の運動時間が制限にあっているのか、そして足りないなら少なくともあと何分運動する必要があったのかを計算するプログラムを作成することにした。
●制約
- ああああ
●入力
入力は以下の形式で標準入力から与えられる。
L H
N
A1
A2
:
AN
- 1 行目には、2 個の整数 L, H(1≦L≦H≦10^4 ) が空白区切りで与えられる。これは、高橋君が週に L 分以上 H 分以下の運動をしなければならないことを表す。
- 2 行目には、整数 N(1≦N≦50) が与えられる。これは青木君が N 週分の運動時間について調べていることを表す。
- 3 行目からの N 行には、高橋君の運動状況を表す整数が与えられる。N 行の内 i(1≦i≦N) 行目には、整数 Ai (0≦Ai ≦10^4 ) が与えられる。これは i 個前の週において高橋君が Ai 分運動したことを表す。
●出力
出力は N 行からなる。i(1≦i≦N) 行目には、i 個前の週において高橋君が必要な分よりも多く運動している場合は −1 を、そうでない場合は追加で必要な運動時間の最小値を分単位で 1 行に出力せよ。 出力の末尾にも改行を入れること。
■回答
●愚直に書く
久しぶりのB問題。 まずは標準入力をちゃんと取るところから。
l, h = gets.split.map(&:to_i)
n = gets.to_i
a = n.times.map do |line|
line = gets.to_i
end
# 以下は確認用
p l, h
p n
p a
これで標準入力は取れた。
次に、配列aの各要素がl
以上h
以下かどうかを判定していく感じか。
l, h = gets.split.map(&:to_i)
n = gets.to_i
a = n.times.map do |line|
line = gets.to_i
end
a.each do |elm|
if elm < l
puts l - elm
elsif elm > h
puts -1
else
puts 0
end
end
通った!
●メソッド化して書く
メソッドを作る練習のために、あえてそういう書き方をする。
メインメソッド、判定用メソッド、標準入力を取るメソッド2つの計4つ。 メインメソッド内のeachを回す部分をさらに別メソッドに分けても良いかな?
def main
l, h = read_target
a = read_record
a.each do |elm|
puts judge(l, h, elm)
end
end
def judge(l, h, elm)
if elm < l
l - elm
elsif elm > h
-1
else
0
end
end
def read_target
gets.split.map(&:to_i)
end
def read_record
n = gets.to_i
n.times.map do |line|
line = gets.to_i
end
end
main
通った!
●リファクタリング/別アプローチ
色々試したけど上手く整理できなかったので割愛…!
●他の方の回答例
max
を使った解答があり、なるほどと思った。
自分の回答に取り入れると以下のような感じ。
l, h = gets.split.map(&:to_i)
n = gets.to_i
a = n.times.map do |line|
line = gets.to_i
end
a.each do |elm|
if elm <= h
puts [l - elm, 0].max
else
puts -1
end
end
これだとif内がシンプルになるしそれによって三項演算子にもしやすい。なるほど。
●出てきたメソッド等
公式リファレンスを見る訓練。
- instance method Array#max https://docs.ruby-lang.org/ja/latest/method/Array/i/max.html
- instance method Comparable#between? https://docs.ruby-lang.org/ja/latest/method/Comparable/i/between=3f.html
■振り返りなど
計算するのにちょっと混乱してしまった。 とはいえB問題を愚直にでも解けたので良かった。