問題は以下を参照して下さい。
たんに四重ループ総当りで解ける簡単な問題ですが、Rubyらしくというのにこだわってみました。コードは以下です。
atcoder224b.rb
h, w = gets.split.map(&:to_i)
a = h.times.map { gets.split.map(&:to_i) }
def selected_loop(x)
x.pred.times do |i1|
(i1.next...x).each do |i2|
yield(i1, i2)
end
end
end
e = Enumerator.new do |y|
selected_loop(h) do |i1, i2|
selected_loop(w) do |j1, j2|
y << (a[i1][j1] + a[i2][j2] <= a[i2][j1] + a[i1][j2])
end
end
end
puts e.all? ? "Yes" : "No"
総当りの四重ループですが、行方向と列方向のループが同様に書けるので、自分でイテレータ(繰り返し用のメソッド)を定義してみました。それがselected_loop
メソッドで、「ブロック」のついたメソッドとして定義されています。yield
がありますよね。ブロック変数には、行あるいは列方向に、あらかじめ条件を満たした数値が順に入ります。
もうひとつ工夫したのは、すべての判定をEnumerator
化しているということです。変数e
がそれです。問題の条件は、すべての判定が真なら Yes を出力せよということなので、それをEnumerable#all?
メソッドでやりたかったのですね。
競プロで自分でイテレータ用メソッドを定義したり、Enumerator
をそれらしく使えたりする問題はあまりないので、趣味的にこだわってみました笑。
なお、この解法は短くもありませんし、速くもありません。ただ、可読性は多少よいのかなと思っています。