コンテンツへスキップ

【Ruby基礎】AtCoder Beginner Contest 032 A – 高橋君と青木君の好きな数

■はじめに

Rubyの基礎的な問題をたくさん解くことで基本的な考え方やメソッドの使い方を定着させたい。
基本的にはAtCoderというプログラミングコンテスト(競技プログラミング)の過去問を使う。(AtCoderは難易度が分かれており、難易度の低いA問題かB問題を解いていく)

(5/23時点の方針)
メソッドの切り分け方や値の受け渡しを練習するために、コード長の短さについては気にせずに書くことにする。

■問題

●出典

AtCoder Beginner Contest 032のA問題
https://atcoder.jp/contests/abc032/tasks/abc032_a

●問題文

青木君は整数 a で割り切れる数が好きです。 高橋君は整数 b で割り切れる数が好きです。
n 以上の整数で、青木君と高橋君の両方が好きな最小の数を答えてください。

●入力

入力は以下の形式で標準入力から与えられる。

a
b
n
  • 1 行目には、整数 a(1≦a≦100) が与えられる。
  • 2 行目には、整数 b(1≦b≦100) が与えられる。
  • 3 行目には、整数 n(1≦n≦20,000) が与えられる。

●出力

出力は以下の形式で標準出力に行うこと。
1 行目に、n 以上の整数で青木君と高橋君の両方が好きな数の最小値を出力せよ。末尾の改行を忘れないこと。

■回答

●愚直に書く

複数行の標準入力をパッと取るにはどうするんだっけ。。。
一旦愚直に3行かいて取る。

a = gets.to_i
b = gets.to_i
n = gets.to_i
p a
p b
p n

これで取れた。

肝心の中身について。
aとbの公倍数でn以上の最小値を出せってことか。

これは、僕の苦手な、数値を足し上げていくやつか…?
あと、公倍数を出すの難しい。
公倍数を出さなくても、「aで割り切れて、かつbで割り切れるまで、nを1つずつ増やしていく」という感じでどうか。

a = gets.to_i
b = gets.to_i
n = gets.to_i

result = n
until result % a == 0 && result % b == 0 do
  result += 1
end
p result

通った!嬉しい。

●メソッド化して書く

メソッドを作る練習のために、あえてそういう書き方をする。

def main
  a = read_a
  b = read_b
  n = read_n
  until n % a == 0 && n % b == 0 do
    n += 1
  end
  puts n
end

def read_a
  gets.to_i
end

def read_b
  gets.to_i
end

def read_n
  gets.to_i
end

main

通った!!

●リファクタリング/別アプローチ

もうちょいスッキリできないものか…。
カウントアップしていく部分を別メソッドにしてみる。

def main
  a = read_a
  b = read_b
  n = read_n
  puts countup(a, b, n)
end

def countup(a, b, n)
  until n % a == 0 && n % b == 0 do
    n += 1
  end
  n
end

def read_a
  gets.to_i
end

def read_b
  gets.to_i
end

def read_n
  gets.to_i
end

main

通った!
でもcountupメソッドの最後のnだけちょこんって置いてあるのがなんか違和感なのだけど、これで問題ないのか、直す余地があるのか、わからない。

●他の方の回答例

わからない書き方も多いけど、色々勉強になる…!

まず、3行の標準入力を1発で取るのはこれとか。

a,b,n = 3.times.map{gets.to_i}

そして最小公倍数を得るメソッドがあった…!

10.lcm(4)
# => 20

ただ、求める値を出すための式として以下の(n + ab - 1) / ab * abの式を書いてる方がたくさんいるけど、これがよくわからない…。

a, b, n = 3.times.map{gets.to_i}
ab = a.lcm(b)
puts (n + ab - 1) / ab * ab

nと最小公倍数を足して1引いて、それを最小公倍数の二乗で割ると答えになるの??
例えばa=2 b=3 n=8だとして…。

n + ab - 1 / ab * ab
= (8 + 6 - 1) / 6 * 6
= 13 / 6 * 6
= 2 * 6

ちゃんと答えになったわ…。
「それを最小公倍数の二乗で割る」が間違ってた。
指揮の順番としては、
「nと最小公倍数を足して1引いて、それを最小公倍数で一度割ってから、最小公倍数でかける」
が正しい。前半の割り算の部分は、Integer同士で割るから余りがうまく消えて、そこにもう一度最小公倍数をかけることで求める値が出る、ということか。
これはRubyじゃなくて数学的な部分の頭が追いつかなかった…涙。

あと、標準入力の取り方をシンプルにする方法がわかったのでメソッド化する方法の方をもう少しスッキリさせてみた。

def main
  a, b, n = read_number(a, b, n)
  puts countup(a, b, n)
end

def countup(a, b, n)
  until n % a == 0 && n % b == 0 do
    n += 1
  end
  n
end

def read_number(a, b, n)
  a, b, n = 3.times.map{gets.to_i}
end

main

通った!

●出てきたメソッド等

公式リファレンスを見る訓練。

■振り返りなど

標準入力の取り方、untilを使った回し方、最小公倍数を求めるメソッド、算数的な頭の足りなさなど、色々と学びが多かった。