RubyでACM/ICPC vol. 1
引き続き,2004愛媛大会のproblem BをRubyで解いてみました。
プログラムを見れば自明ですが,以下のような方針を再帰で実装しました。
1. '@'の上下左右の黒タイルを'c'(checked)でマークする。
2. マップから'c'タイルを探し,見つからなければ3へ進む。
i. 見つかった'c'タイルを'd'(done)でマークする。
ii. 'd'でマークしたタイルの上下左右の黒タイルを'c'でマークする。
iii. 2に戻る。
3. 'c'でマークしたタイルの数に'@'マークの分の1を加えて出力。
とりあえず,以下のようになりました。
def scan_map(x, y, map, n) return n if x == nil || y == nil n += mark(x, y, map) i, j = get_not_centered(map) scan_map(i, j, map, n) end def mark(x, y, map) map[y][x] = "d" arr = [[y-1, x], [y+1, x], [y, x-1], [y, x+1]] xlim = map[0].size - 1 ylim = map.size - 1 arr.delete_if{|p| p[0] < 0 || p[1] < 0 || p[0] > ylim || p[1] > xlim } count = 0 arr.each{|p| i, j = p[0], p[1] if map[i][j] == "." map[i][j] = "c" count += 1 end } return count end def get_not_centered(map) map.each_with_index{|line, j| line.each_with_index{|val, i| return i, j if val == "c" } } return nil, nil end while line = gets line =~ /(\d+) (\d+)/ w, h = $1.to_i, $2.to_i exit if h == 0 map = [] x, y = 0, 0 h.times{|i| line = gets map[i] = line.chomp!.split(//) y, x = i, map[i].index("@") if map[i].include?("@") } p scan_map(x, y, map, 0) + 1 #add '@' cell end
パターンマッチは1回だけだから目をつぶるとしても,馬鹿正直に'c'タイルを探しているget_not_centered(map)メソッドは効率がよくありません。
(1, 2)のタイルをarr[12]で表すなどすれば1つの配列でmapを表現してみると