Problem:
ペンキの色

問題

情報オリンピックの宣伝のために,長方形のベニヤ板にペンキを塗り看板を制作したい.ベニヤ板には色を塗りたくないところにあらかじめ何枚かの長方形のマスキングテープが貼られている.そこでマスキングテープで区切られた領域ごとに別々の色を使いペンキを塗ることにした.例えば,図 5-1 の場合は 5 色のペンキを使う.

入力としてマスキングテープを貼る位置が与えられた時,使うペンキの色の数を求めるプログラムを作成せよ.ただし,ベニヤ板全体がマスキングテープで覆われることはなく,全てのマスキングテープの辺はベニヤ板のいずれかの辺に平行である.

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．

1 行目にはベニヤ板の幅 w (1 ≤ w ≤ 1000000 となる整数) と高さ h (1 ≤ h ≤ 1000000 となる整数) がこの順に空白区切りで書かれている.

2 行目にはマスキングテープの数 n (1 ≤ n ≤ 1000 となる整数) が書かれている.
続く 3 行目以降の 2 + i 行目 (1 ≤ i ≤ n) には,i 番目に貼るマスキングテープの左下の座標 (x1 , y1 ) と,右上の座標 (x2 , y2 ) が x1 , y1 , x2 , y2 (0 ≤ x1 < x2 ≤ w, 0 ≤ y1 < y2 ≤ h となる整数) の順に空白区切りで書かれている.

ただし,ベニヤ板の左下の角の座標は (0, 0) で右上の角の座標は (w, h) である. 採点用データのうち, 配点の 30% 分は w ≤ 100, h ≤ 100, n ≤ 100 を満たす.

h, w がともに 0 のとき入力の終了を示す. データセットの数は 20 を超えない．

出力

データセットごとに使うペンキの色数を１行に出力する.

入出力例

次の例は図 5-1 の場合である.

入力例

15 6
10
1 4 5 6
2 1 4 5
1 0 5 1
6 1 7 5
7 5 9 6
7 0 9 2
9 1 10 5
11 0 14 1
12 1 13 5
11 5 14 6
0 0

出力例

5

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in Ruby (judge verdict: Accepted)

while true
  w, h = gets.split.map(&:to_i)
  break if w == 0
  xh = {}; yh = {}
  xa = []; ya = []
  xa << 0; xa << w
  ya << 0; ya << h
  points = []
  gets.to_i.times do
    point = gets.split.map(&:to_i)
    points << point
    xa << point[0]; xa << point[2]
    ya << point[1]; ya << point[3]
  end
  xa = xa.uniq; xa.sort!; ya = ya.uniq; ya.sort!
  xs = xa.size; ys = ya.size
  xa.each_with_index{ |a, i| xh[a] = i+1 }
  ya.each_with_index{ |b, i| yh[b] = i+1 }
  fld = Array.new(ys+1){ Array.new(xs+1, true) }
  fld[0].fill(false); fld[ys].fill(false)
  fld.map{ |arr| arr[0] = arr[xs] = false }

  for point in points
    x1, y1, x2, y2 = point
    for a in (yh[y1]...yh[y2])
      for b in (xh[x1]...xh[x2])
        fld[a][b] = false
      end
    end
  end
  ret = 0
  for y in (1...ys)
    for x in (1...xs)
      next unless fld[y][x]
      arr = []
      arr << [y, x]
      until arr.empty?
        ny, nx = arr.shift
        [[-1,0],[0,-1],[1,0],[0,1]].each do |dy, dx|
          px = nx+dx; py = ny+dy
          if fld[py][px]
            arr << [py, px] 
            fld[py][px] = false
          end
        end
      end
      ret += 1
    end
  end
  p ret
end