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: Memory Limit Exceeded)

#include<iostream>
#include<map>
#include<vector>
#include<cstdio>
#include<algorithm>
#include<sstream>
#include<queue>
#include<cassert>
#include<deque>
#include<set>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define inf (1<<29)
#define all(n) (n).begin(),(n).end()
#define MAX 12
#define sinf (10000)

using namespace std;

typedef unsigned short us;
typedef unsigned char uc;

struct Pox
{
  vector<uc> array;
  int cost;
  us prev;
  Pox(vector<uc> array=vector<uc>(),int cost=sinf,us prev=sinf):array(array),cost(cost),prev(prev){}
  bool operator < (const Pox &a)const
  {
    return cost > a.cost;
  }
};

int dx[] = {1,0,-1,0};
int dy[] = {0,-1,0,1};
int max_ans;
//int dx[] = {0,1,0,-1};
//int dy[] = {1,0,-1,0};
int ev[MAX*MAX][MAX*MAX];//評価値 ev[a][b] := aからbまでの最短コスト
char g[MAX][MAX];
int st[2],h,w,ice_number;
int ice[MAX*MAX];
int ice_cnt[MAX*MAX];
set<vector<uc> > mincost;
//set<ull> mincost;
//priority_queue<Pox> Q;
//queue<Pox> Q;
deque<Pox> Q;



void init()
{
  max_ans = 0;
  // while(!Q.empty())Q.pop_back();
  ice_number = 0;
  rep(i,h)rep(j,w)ice[j+i*w] = ice_cnt[j+i*w] = inf;
  //rep(i,h*w)rep(j,h*w)ev[i][j] = inf;
  mincost.clear();
}

void getInput()
{
  rep(i,h)
    {
      getchar();
      rep(j,w)
	{
	  scanf("%c",&g[i][j]);
	  if(g[i][j] == 'S')
	    {
	      st[0] = j + i * w;
	      g[i][j] = '.';
	    }
	  if(g[i][j] == 'G')
	    {
	      st[1] = j + i * w;
	      g[i][j] = '.';
	    }
	  if(g[i][j] == '.')max_ans++;
	}
    }
}

void make_ev()
{
  rep(sp,h*w)
    {
      ev[sp][sp] = 0;
      deque<int> deq;
      deq.push_back(sp);

      while(!deq.empty())
	{
	  int cur = deq.front(); deq.pop_front();
	  if(cur == st[1])break;
	  rep(i,4)
	    {
	      int nx = cur % w + dx[i];
	      int ny = cur / w + dy[i];
	      if(!(0 <= nx && nx < w && 0 <= ny && ny < h))continue;
	      if(g[ny][nx] == '#')continue;
	      if(ev[sp][nx+ny*w] > ev[sp][cur]+1)
		{
		  ev[sp][nx+ny*w] = ev[sp][cur]+1;
		  deq.push_back(nx+ny*w);
		}
	    }
	}
    }
}

void draw(int cur,int id,int &cnt)
{
  if(ice[cur] != inf)return;
  ice[cur] = id;
  cnt++;
  rep(i,4)
    {
      int nx = cur % w + dx[i];
      int ny = cur / w + dy[i];
      if(!(0 <= nx && nx < w && 0 <= ny && ny < h))continue;
      if(g[ny][nx] != 'X')continue;
      draw(nx+ny*w,id,cnt);
    }
}

bool compute(int depth)
{

  while(!Q.empty())
    {
      Pox pox = Q.front(); Q.pop_front();

      //cnt++;
      //if(pox.cost + ev[pox.array[ice_number]][st[1]] >= max_ans)continue;
      //if(cnt > 10 && !Q.empty() && (cnt%60 == 0 || cnt %120 == 0 || cnt % 73 == 0))Q.pop();
      // int cost = pox.cost + ev[pox.array[ice_number]][st[1]];
      //if(cost >= ev[st[0]][st[1]]*5)continue;
      /*
      if( (cnt % 666 == 0|| cnt % 700 == 0) && !Q.empty())
	{
	  Pox pre = pox;
	  pox = Q.front(); Q.pop_front();
	  continue;
	  //Q.push(pre);
	}
      */
      /*
      if(cnt >= 100 && cnt % 3 == 0 && Q.size() >= 2)
	{
	  Pox store = pox;
	  Pox store2 = Q.top(); Q.pop();
	  pox = Q.top(); Q.pop();
	  Q.push(store);
	  Q.push(store2);
	}
      */
      /*
      if(cnt >= 100 && cnt % 7 == 0 && Q.size() >= 5)
	{
	  Pox store[3];
	  store[0] = pox;
	  rep(i,2)
	    {
	      store[i+1] = Q.top(); Q.pop();
	    }
	  pox = Q.top(); Q.pop();
	  rep(i,3)Q.push(store[i]);
	}
      */
      /*
      cout << "pox:array:\n";
      rep(i,pox.array.size())
	cout << "array[" << i << "] = " << pox.array[i] << endl;
      cout << "pox:cost:" << pox.cost << endl << endl;
      */
      if(st[1] == pox.array[ice_number])
	{
	  //printf("h\n",pox.cost);
	  cout << pox.cost << endl;
	  return true;
	}

      if(pox.cost + ev[pox.array[ice_number]][st[1]] >= max_ans)
	{
	  continue;
	}

      if(pox.cost + ev[pox.array[ice_number]][st[1]] >= depth)
	{
	  Q.push_back(pox);
	  return false;
	}


      rep(i,4)
	{
	  if(pox.prev != -1 && pox.prev == (i+2)%4)continue;
	  int nx = pox.array[ice_number] % w + dx[i];
	  int ny = pox.array[ice_number] / w + dy[i];
	  if(!(0 <= nx && nx < w && 0 <= ny && ny < h))continue;
	  if(g[ny][nx] == '#')continue;

	  vector<uc> next = pox.array;	
	  next[ice_number] = nx+ny*w;  

	  if(g[ny][nx] == 'X')
	    {
	      if(ice_cnt[ice[nx+ny*w]] < 2*(pox.array[ice[nx+ny*w]] + 1))continue;

	      next[ice[nx+ny*w]]++;
	    }


	  if(mincost.find(next) == mincost.end())
	    {
	      mincost.insert(next);
	      if(Q.front().cost > pox.cost+1)
		Q.push_front(Pox(next,pox.cost+1,i));
	      else
		Q.push_back(Pox(next,pox.cost+1,i));
	    }
	}
    }
  return false;
}

int main()
{
  //while(scanf("h h",&w,&h),w|h)
  while(cin >> w >> h,w|h)
    {
      init();
      getInput();
      make_ev();

      rep(y,h)rep(x,w)
	if(g[y][x] == 'X' && ice[x+y*w] == inf)
	    {
	      int cnt = 0;
	      draw(x+y*w,ice_number,cnt);
	      ice_cnt[ice_number] = cnt;
	      ice_number++;      
	    }

      rep(i,ice_number)max_ans += ice_cnt[i];

      vector<uc> initial_array(ice_number+1,0);
      initial_array[ice_number] = st[0];
      Q.push_back(Pox(initial_array,0,-1));
      mincost.insert(initial_array);
      int depth = 0;
      while(!compute(depth++));	
      while(!Q.empty())Q.pop_back();
    }
  return 0;
}