Problem:
氷の迷路

四角のマスを縦横にならべた長方形の迷路があります。この迷路では東西南北の隣接するマスへ移動しながら、スタートのマスSを出発し、ゴールのマスGを目指します。マスの種類には、平原、山、氷の３種類があります。SとGは、平原のマスに置かれています。平原のマスには移動できますが、山のマスには移動できません。氷のマスは移動できますが、条件によって氷が割れ動けなくなります。

氷のマスは東西南北に隣接するもの全体でひとつの塊として扱われます。

氷の塊のなかで、マスの個数の半分より多くのマスに移動すると、塊全体が割れます。

例えば、図１は与えられた迷路の最短経路のステップ数が 11 であることを示しています。

図1

しかし、図２のように氷のマスを通って近道をしようとすると、大きさが６の氷の塊に対する４回目の移動後に動けなくなってしまいGには到達できません。

図2

このような迷路の情報を入力とし、SからGまでの最短経路のステップ数を求めるプログラムを作成してください。マスの種類はそれぞれ以下の文字で表されます：

文字（半角）

マスの種類

. （ピリオド）

平原

#（シャープ）

山

X

氷

与えられる迷路は必ず解けるものとします。迷路はその東西方向のマスの数 X、南北方向のマスの数 Y と X × Y 個の文字として与えられます。

入力

複数のデータセットが与えられます。入力の終わりはゼロふたつの行で示されます。各データセットは以下の形式で与えられます。

X Y
line1
line2
:
lineY

1行目に迷路の大きさを表す整数 X, Y (2 ≤ X, Y ≤ 12) が与えられます。続く Y 行に迷路の i 行目の情報 linei (長さ X の半角英文字列) が与えられます。

データセットの数は 40 を超えない。

出力

データセットごとに、最小のステップ数を１行に出力します。

入力例

5 5
.X.S.
.X#..
.XX##
.#XG.
..X..
7 3
SXX.XXG
X.#.#X.
XXX.XX#
4 4
S...
X.X.
GX..
...X
10 10
..XXXXX.XX
.X.#.#X.XX
SX.#X.X..X
#X.##.X.XX
..XXXX#.XX
##.##.##XX
....X.XX#X
.##X..#X#X
....XX#..X
...#XXG..X
0 0

出力例

11
10
10
33

Solution in Ruby (judge verdict: Time Limit Exceeded)

### constant

MAX_INT = (1 << 30)
DXYS = [[1, 0], [0, -1], [-1, 0], [0, 1]]

### main

while true
  $w, $h = gets.strip.split(' ').map{|s| s.to_i}
  $wh = $w * $h
  break if $w == 0 && $h == 0

  start = nil
  goal = nil
  brds = []

  for y in (0...$h)
    hl = gets.strip
    for x in (0...$w)
      pos = y * $w + x
      case hl[x]
      when '.'
        brds[pos] = -1
      when '#'
        brds[pos] = nil
      when 'X'
        brds[pos] = 'X'
      when 'S'
        start = pos
        brds[pos] = -1
      when 'G'
        goal = pos
        brds[pos] = -1
      end
    end
  end

  nice = 0
  ices = []

  for y in (0...$h)
    for x in (0...$w)
      pos = y * $w + x
      if brds[pos] == 'X'
        ices[nice] = 1
        brds[pos] = nice
        q = [pos]

        while ! q.empty?
          pos0 = q.shift
          x0 = pos0 % $w
          y0 = pos0 / $w

          for dxy in DXYS
            x1 = x0 + dxy[0]
            y1 = y0 + dxy[1]
            pos1 = y1 * $w + x1
            if x1 >= 0 && x1 < $w && y1 >= 0 && y1 < $h && brds[pos1] == 'X'
              ices[nice] += 1
              brds[pos1] = nice
              q << pos1
            end
          end
        end

        nice += 1
      end
    end
  end

  ices.map!{|k| k / 2 }

  #p brds
  #p ices

  dists = $wh.times.map{Hash.new(MAX_INT)}
  dists[start][ices] = 0
  q = [[start, ices]]

  while ! q.empty?
    #p q

    nd = q.min{|a, b| dists[a[0]][a[1]] <=> dists[b[0]][b[1]]}
    q.delete nd

    pos, ics = nd
    break if pos == goal

    x = pos % $w
    y = pos / $w

    for dxy in DXYS
      x0 = x + dxy[0]
      y0 = y + dxy[1]

      if x0 >= 0 && x0 < $w && y0 >= 0 && y0 < $h
        pos0 = y0 * $w + x0
        ic = brds[pos0]
        next if ic.nil?

        if ic >= 0
          next if ics[ic] <= 0
          ics0 = ics.clone
          ics0[ic] -= 1
        else
          ics0 = ics
        end

        d0 = dists[pos][ics] + 1
        if dists[pos0][ics0] > d0
          dists[pos0][ics0] = d0
          q << [pos0, ics0]
        end
      end
    end
  end
  #p dists

  puts dists[goal].values.min
end