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 C++ (judge verdict: Time Limit Exceeded)

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;

const int MAXH = 13;
const int MAXW = 13;
const int di[] = {0,1,0,-1};
const int dj[] = {1,0,-1,0};
const int INF = 1<<28;

int W, H;
char G[MAXH][MAXW];
int si, sj, ti, tj;
int N;
int ice[MAXH][MAXW];
int ans;
bool vis[MAXH][MAXW];
int cnt[1000];
int fromG[MAXH][MAXW];

int dfs(int pi, int pj, int n) {
  int res = 1;
  ice[pi][pj] = n;
  for(int k = 0; k < 4; ++k) {
    int ni = pi + di[k];
    int nj = pj + dj[k];
    if(ni < 0 || ni >= H) continue;
    if(nj < 0 || nj >= W) continue;
    if(G[ni][nj] != 'X') continue;
    if(ice[ni][nj] != -1) continue;
    res += dfs(ni, nj, n);
  }
  return res;
}

void bfs(int si, int sj) {
  queue<pair<int,int> > que;
  fill(fromG[0], fromG[MAXH], INF);
  que.push(make_pair(si,sj));
  fromG[si][sj] = 0;
  while(que.size()) {
    int pi = que.front().first;
    int pj = que.front().second;
    que.pop();
    for(int k = 0; k < 4; ++k) {
      int ni = pi + di[k];
      int nj = pj + dj[k];
      if(ni < 0 || ni >= H) continue;
      if(nj < 0 || nj >= W) continue;
      if(G[ni][nj] == '#') continue;
      if(fromG[ni][nj] != INF) continue;
      que.push(make_pair(ni,nj));
      fromG[ni][nj] = fromG[pi][pj] + 1;
    }
  }
}

void dfs2(int pi, int pj, int cost) {
  if(cost+fromG[pi][pj] >= ans) return;
  if(pi == ti && pj == tj) {
    ans = min(ans, cost);
    return;
  }

  vis[pi][pj] = true;
  vector<pair<int,pair<int,int> > > v;
  for(int k = 0; k < 4; ++k) {
    int ni = pi + di[k];
    int nj = pj + dj[k];
    if(ni < 0 || ni >= H) continue;
    if(nj < 0 || nj >= W) continue;
    if(vis[ni][nj]) continue;
    if(G[ni][nj] == '#') continue;
    if(G[ni][nj] == 'X' && cnt[ice[ni][nj]] == 0) continue;
    v.push_back(make_pair(fromG[ni][nj], make_pair(ni,nj)));
  }
  sort(v.begin(), v.end());
  for(int i = 0; i < v.size(); ++i) {
    int ni = v[i].second.first;
    int nj = v[i].second.second;
    if(G[ni][nj] == 'X') cnt[ice[ni][nj]] -= 1;
    dfs2(ni, nj, cost+1);
    if(G[ni][nj] == 'X') cnt[ice[ni][nj]] += 1;
  }
  vis[pi][pj] = false;
}

int main() {
  while(cin >> W >> H && (W|H)) {
    for(int i = 0; i < H; ++i) {
      for(int j = 0; j < W; ++j) {
        cin >> G[i][j];
        if(G[i][j] == 'S') {
          si = i;
          sj = j;
          G[i][j] = '.';
        }
        if(G[i][j] == 'G') {
          ti = i;
          tj = j;
          G[i][j] = '.';
        }
      }
    }
    fill(ice[0], ice[MAXH], -1);
    N = 0;
    for(int i = 0; i < H; ++i) {
      for(int j = 0; j < W; ++j) {
        if(G[i][j] == 'X' && ice[i][j] == -1) {
          cnt[N] = dfs(i, j, N)/2;
          ++N;
        }
      }
    }
    bfs(ti, tj);
    ans = INF;
    fill(vis[0], vis[MAXH], 0);
    dfs2(si, sj, 0);
    cout << ans << endl;
  }
  return 0;
}