はじめに
育児の合間にAtCoderのBeginners Selectionの問題を少しづつ解いています。
やってみた感想
自分のプログラムの書けなさっぷりに衝撃を受けました。
SIerでプロジェクトリーダーやPJ管理の仕事ばかりしていたため、プログラムを書いてきた時間が圧倒的に足りていません。今の自分のレベルは、A問題やB問題がかろうじて解けるレベルだと思います。
今の自分の立ち位置を真摯に受け止め、少しずつレベルアップしていきたいと思います。
第 1 問: ABC 086 A - Product (100 点)
問題
書いたプログラム(Ruby)
# 入力:整数a b # 出力:積が奇数なら Odd と、 偶数なら Even と出力せよ。 a,b = gets.chomp.split(" ").map(&:to_i) c = a * b if c % 2 == 0 puts("Even") else puts("Odd") end
デバッグ
$ ruby ABC086A/answer.rb 3 4 Even $ ruby ABC086A/answer.rb 1 21 Odd
結果
無事にAC
を取れました。
類題:ABC 088 A - Infinite Coins (倍数判定の発展として、余りを計算します)
問題
書いたプログラム(Ruby)
# 出力:E869120 の持っている 1 円硬貨と 500 円硬貨だけで, ちょうど N 円を支払うことができるならば Yes, そうでないならば No を出力しなさい. # 支払金額 n = gets.to_i # 500円は無限 # 持っている1円の枚数 a = gets.to_i if n % 500 <= a puts("Yes") else puts("No") end
デバッグ
$ ruby abc088_a/answer.rb 2018 218 Yes $ ruby abc088_a/answer.rb 2763 0 No
結果
無事にAC
を取れました。
第 2 問: ABC 081 A - Placing Marbles (100 点)
問題
書いたプログラム(Ruby)
for
で書く。1行で書くこともできる。
# 1の場合はビー玉を置く # 文字列の取得 str = gets.chomp num = 0 # for文を使って書く for i in 0..str.size do num += 1 if str[i] == '1' end # 出力 p num # 1行で書く # p gets.chomp.count("1")
デバッグ
$ ruby abc081_a/answer.rb 101 2 $ ruby abc081_a/answer.rb 000 0
第 3 問: ABC 081 B - Shift Only (200 点)
問題
書いたプログラム(Ruby)
# 与えられた整数がすべて偶数なら、すべての整数を2で割ったものに置き換える # 入力 n = gets.chomp.to_i nums = gets.chomp.split(" ").map(&:to_i) count = 0 # 整数かどうか判断 # 偶数ならevenメソッド # 奇数ならoddメソッド # すべて2で割れるなら2で割ったものに置換する # a,b,cいずれかが2で割り切れなくなるまで繰り返す # selectメソッド # 条件に合致する要素を取り出す # collectメソッド # 要素の数だけ繰り返しブロックを実行し、ブロックの戻り値を集めた配列を作成する # collect!でレシーバ自身を変更する while nums.select(&:odd?).empty? do nums.collect! {|num| num /= 2} count += 1 end # 出力 p count
第 4 問: ABC 087 B - Coins (200 点)
問題
書いたプログラム(Ruby)
# 500円の枚数 A = gets.chomp.to_i # 100円の枚数 B = gets.chomp.to_i # 50円の枚数 C = gets.chomp.to_i # xは50の倍数 X = gets.chomp.to_i # a,b,cの組合せの中に、xがあるか? count = 0 for a in 0..A do for b in 0..B do for c in 0..C do # 金額計算 count += 1 if (500 * a) + (100 * b) + (50 * c) == X end end end # 出力 p count
第 5 問: ABC 083 B - Some Sums (200 点)
問題
中間成果物のデバッグ
2.4.0 :003 > def digit_sum n 2.4.0 :004?> sum = 0 2.4.0 :005?> while n > 0 do 2.4.0 :006 > sum += n % 10 2.4.0 :007?> n /= 10 2.4.0 :008?> end 2.4.0 :009?> sum 2.4.0 :010?> end => :digit_sum 2.4.0 :011 > (1..20).map{ |i| [i, digit_sum(i)]} => [[1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [10, 1], [11, 2], [12, 3], [13, 4], [14, 5], [15, 6], [16, 7], [17, 8], [18, 9], [19, 10], [20, 2]] 2.4.0 :013 > (1..20).map{ |i| [i, digit_sum(i)]}.select { |d| 2 <= d[1] && d[1] <= 5 } => [[2, 2], [3, 3], [4, 4], [5, 5], [11, 2], [12, 3], [13, 4], [14, 5], [20, 2]] 2.4.0 :014 > (1..20).map{ |i| [i, digit_sum(i)]}.select { |d| 2 <= d[1] && d[1] <= 5 }.inject(0) { |sum, d| sum + d[0] } => 84
書いたプログラム(Ruby)
N,A,B = gets.chomp.split(' ').map(&:to_i) # N以下の整数 # 各桁の和が、A以上B以下の合計を出力する def find_sum_of_digits n sum = 0 while (n > 0) # 10で割った余りを足すのが定石 sum += n % 10 n /= 10 end return sum end sum = 0 total = 0 for n in 1..N do # 各桁の和を求める sum = find_sum_of_digits n if sum >= A && sum <= B total += n end n += 1 end p total
別の解き方
inject
メソッドを使って解くともっと楽。
injectメソッドとは
inject (Enumerable) - Rubyリファレンス
injectメソッドは、ブロックを使って繰り返し計算を行うのに使います。ブロックに順に「要素1、要素2」、「ブロックの前回の戻り値、要素3」、「ブロックの前回の戻り値、要素4」、...を渡します。メソッドの戻り値はブロックが最後に返した値になります。
引数initで初期値を指定すると、ブロックに「初期値、要素1」、「ブロックの前回の戻り値、要素2」、「ブロックの前回の戻り値、要素3」、...を渡します。
2.4.0 :015 > numbers = [4, 3, 9, 8, 5, 6, 1, 7, 2] => [4, 3, 9, 8, 5, 6, 1, 7, 2] 2.4.0 :016 > puts numbers.inject {|sum, n| sum + n } 45 => nil 2.4.0 :018 > puts numbers.inject(100) {|diff, n| diff - n} 55 => nil
参考サイト
2.4.0 :019 > sum = 0 => 0 2.4.0 :020 > (1..10).each {|i| sum += i} => 1..10 2.4.0 :021 > puts sum 55 => nil # こう書いても同じ 2.4.0 :024 > (1..10).inject(0){|sum, i| sum += i} => 55 # 初期値は省略可能 2.4.0 :025 > (1..10).inject {|sum,i| sum += i} => 55 # シンボルを渡すこともできる。すごい! 2.4.0 :026 > (1..10).inject(:+) => 55
おわりに
本エントリでは、AtCoder Beginners Selectionの5問目までを解きました。プログラミングも急に書けるようになるわけではなく、毎日地道にこつこつ書いてこそだと思います。プログラミングも紙一重の努力を積み重ねます!