はじめに
Webエンジニアを目指して、RubyやRailsをいじってます。
今回は、RubyでAtCoder ABC295のA, B, Cを解きました。備忘録として解き方をまとめていきたいと思います。
A - Probably English
# 修正前
n = gets.to_i
w = gets.split(" ")
arr = ["and", "not", "that", "the", "you"]
w.each do|i|
if arr.include?(i)
puts "Yes"
exit
end
end
puts "No"
# 修正後
n = gets
w = gets.split(" ")
arr = ["and", "not", "that", "the", "you"]
- puts w.any?{ |i| arr.any?{ |j| i == j}} ? "Yes" : "No"
# includeメソッドを使った方が直感的にわかりやすい
+ puts w.any?{ |i| arr.include?(i)} ? "Yes" : "No"
<追記>
コメントでいただいた別解になります。配列["and", "not", "that", "the" "you"]を引いて配列の大きさが変化するかどうかで判定しています。なお、%wで配列の[]を表すことができるようです。
gets
words = gets.split
w = words - %w(and not that the you)
puts words.size == w.size ? "No" : "Yes"
解説
方針として、Nが小さいので全探索していくことにします。
要素にand, not, that, the, youをもつarr配列をあらかじめ用意しておき、文字列wの要素にこれらのいずれかが含まれていればYesを出力して、含まれるものがなければNoを出力するようにしました。
B - Bombs
# 修正前
r, c = gets.split.map(&:to_i)
b = []
r.times do
b << gets.chomp
end
arr = Array.new(r){Array.new(c, false)}
r.times do|i|
c.times do|j|
next if b[i][j] == "#" || b[i][j] == "."
d = b[i][j].to_i
r.times do|k|
c.times do|l|
arr[k][l] = true if (i - k).abs + (j - l).abs <= d
end
end
end
end
r.times do|i|
c.times do|j|
b[i][j] = "." if arr[i][j]
end
end
r.times do|i|
puts b[i]
end
# 修正後
r, c = gets.split.map(&:to_i)
b = Array.new(r){gets.chomp}
arr = Array.new(r){Array.new(c, false)}
r.times do|i|
c.times do|j|
next if b[i][j] == "#" || b[i][j] == "."
d = b[i][j].to_i
r.times do|k|
c.times do|l|
arr[k][l] = true if (i - k).abs + (j - l).abs <= d
end
end
end
end
r.times do|i|
c.times do|j|
b[i][j] = "." if arr[i][j]
end
end
puts b
<追記>
コメントでいただいた別解になります。メソッドを定義して呼び出すことにより実装しているようです。
r, c = gets.split.map(&:to_i)
field = Array.new(r) { gets.chomp }
define_method(:explode) do |x, y, dis, &bk|
(-dis..dis).each do |d1|
rest = dis - d1.abs
(-rest..rest).each do |d2|
x1 = x + d1
y1 = y + d2
unless y1 < 0 || y1 >= r || x1 < 0 || x1 >= c
bk.call(x1, y1)
end
end
end
end
plain_field = field.map { _1.tr("1-9", ".") }
(0...r).each do |y|
(0...c).each do |x|
d = field[y][x].to_i
if d > 0
explode(x, y, d) { |bx, by| plain_field[by][bx] = "." }
end
end
end
puts plain_field
解説
(他の方の提出結果を参考にしました)
方針として、RとCが小さいので4重ループを回していきます。
まず、arr配列で爆弾があるマスからのマンハッタン距離が威力以下であればtrue, そうでなければfalseとしてもちます。そして、trueであれば空きマス(.)になるので変更しています。最後に爆発後の盤面を出力すればOKです。
C - Socks
# 修正前
n = gets.to_i
a = gets.split.map(&:to_i)
hash = Hash.new(0)
a.each do|i|
hash[i] += 1
end
ans = 0
hash.keys.each do|key|
ans += hash[key] / 2
end
puts ans
# 修正後
n = gets
a = gets.split.map(&:to_i)
hash = a.tally
puts hash.values.sum{ |v| v / 2}
解説
まず、同じ色の靴下がそれぞれの色に対して何枚あるかを連想配列hashにもたせます。答えは、それぞれの色の靴下の枚数を2で割った商の合計になります。
メモ
・Enumerable#tally:Array.tallyのように使い、valueが、keyの出現回数であるようなHashを返す。
終わりに
マスを扱う問題が苦手なので、B問題よりもC問題の方が簡単に感じました。質より量、数をこなして苦手意識をなくしていきたいと思います!
参考