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

#include<iostream>
#include<vector>
#include<tuple>
#include<map>
#include<algorithm>
using namespace std;

enum {FLOOR = -3, WALL, ICE};

enum {Y, X};
const int NEXT[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

const int NIL = -1;
const int INF = 1000000000;

int h, w;
vector<vector<int>> field;
vector<int> durability;
int sy, sx, gy, gx;
vector<vector<int>> visited;

int flood_fill(int y, int x, int id) {
    int result = 1;
    field[y][x] = id;
    for(const auto& d: NEXT) {
        int ny = y + d[Y];
        int nx = x + d[X];
        if(field[ny][nx] != ICE) continue;
        result += flood_fill(ny, nx, id);
    }
    return result;
}

int distance(int y, int x) {return abs(gy - y) + abs(gx - x);}

int dfs(int y, int x, int step) {
    if(y == gy && x == gx) return step;
    if(step == 0) return NIL;
    if(distance(y, x) > step) return NIL;
    int result = NIL;
    for(const auto& d: NEXT) {
        int ny = y + d[Y];
        int nx = x + d[X];
        if(field[ny][nx] == WALL) continue;
        if(field[ny][nx] == FLOOR) {
            if(visited[ny][nx]) continue;
            visited[ny][nx] = 1;
            result = max(result, dfs(ny, nx, step - 1));
            visited[ny][nx] = 0;
        } else {
            if(durability[field[ny][nx]] <= 0) continue;
            if(visited[ny][nx]) continue;
            visited[ny][nx] = 1;
            --durability[field[ny][nx]];
            result = max(result, dfs(ny, nx, step - 1));
            ++durability[field[ny][nx]];
            visited[ny][nx] = 0;
        }
    }
    return result;
}

int solve() {
    visited = vector<vector<int>>(h + 2, vector<int>(w + 2, 0));
    for(int i = 1; i <= INF; ++i) {
        int result = dfs(sy, sx, i);
        if(result != NIL) return i - result;
    }
    return NIL;
}

int main() {
    while(cin >> w >> h, w | h) {
        field = vector<vector<int>>(h + 2, vector<int>(w + 2, WALL));
        for(int i = 1; i <= h; ++i) for(int j = 1; j <= w; ++j) {
            char c;
            cin >> c;
            if(c == '#') field[i][j] = WALL;
            else if(c == 'X') field[i][j] = ICE;
            else {
                field[i][j] = FLOOR;
                if(c == 'S') {sy = i; sx = j;}
                if(c == 'G') {gy = i; gx = j;}
            }
        }

        durability.clear();
        for(int i = 1; i <= h; ++i) for(int j = 1; j <= w; ++j) if(field[i][j] == ICE) durability.push_back(flood_fill(i, j, durability.size()) / 2);

        cout << solve() << endl;
    }
}