Problem p00247 (C++)

Buggy submission (status: Memory Limit Exceeded):
#include <algorithm>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <vector>

using namespace std;
typedef pair<int, int> pii;
int H, W;
int sy, sx, gy, gx;
char field[101][101];
int ice;
int iceNumber[101][101];
// iceごとのタイル数
int tileNum[101];
bool used[101][101];
const int dy[] = {-1, 0, 0, 1};
const int dx[] = {0, -1, 1, 0};
int predic[101][101];

// 状態に必要なもの
// ここまでのコスト
// どのiceを何度踏んだか(vectorでもつ)
typedef pair<pii, vector<int>> Info;
typedef pair<int, pair<pii, vector<int>>> Sit;

// 氷を踏む回数を無視したときのgoalからの最短距離
void bfs() {
  queue<pii> q;
  memset(predic, -1, sizeof(predic));
  q.push(pii(gy, gx));
  predic[gy][gx] = 0;
  while (q.size()) {
    pii p = q.front();
    q.pop();
    int cy = p.first;
    int cx = p.second;
    int ccost = predic[cy][cx];
    for (int i = 0; i < 4; i++) {
      int ny = cy + dy[i];
      int nx = cx + dx[i];
      if (ny >= 0 && nx >= 0 && ny < H && nx < W && predic[ny][nx] == -1 &&
          field[ny][nx] != '#') {
        int ncost = ccost + 1;
        predic[ny][nx] = ncost;
        q.push(pii(ny, nx));
      }
    }
  }
}

int astar() {
  priority_queue<Sit, vector<Sit>, greater<Sit>> pq;
  map<Info, int> d;
  vector<int> sv(ice, 0);
  d[(make_pair(pii(sy, sx), sv))] = predic[sy][sx];
  pq.push(Sit(predic[sy][sx], make_pair(pii(sy, sx), sv)));
  int res = 10000000;
  while (pq.size()) {
    Sit p = pq.top();
    pq.pop();
    int cy = p.second.first.first;
    int cx = p.second.first.second;
    int ccost = p.first;
    vector<int> ctile = p.second.second;
    if (d.count(p.second) > 0 && ccost > d[p.second])
      continue;
    int realCost = ccost - predic[cy][cx];
    for (int i = 0; i < 4; i++) {
      int ny = cy + dy[i];
      int nx = cx + dx[i];
      if (ny >= 0 && nx >= 0 && ny < H && nx < W && field[ny][nx] != '#') {
        vector<int> ntile = ctile;
        int ncost = (realCost + 1) + predic[ny][nx];
        Info ninfo = p.second;
        ninfo.first.first = ny;
        ninfo.first.second = nx;
        if (field[ny][nx] == 'X') {
          int a = iceNumber[ny][nx];
          ninfo.second[a]++;
          if (ninfo.second[a] > tileNum[a] / 2)
            continue;
        }
        if (d.count(ninfo) == 0 || d[ninfo] > ncost) {
          d[ninfo] = ncost;
          pq.push(make_pair(ncost, ninfo));
          if (gy == ny && gx == nx)
            res = min(res, ncost);
        }
      }
    }
  }
  return res;
}

int labelling(int cy, int cx, int k) {
  int cnt = 1;
  used[cy][cx] = true;
  iceNumber[cy][cx] = k;
  for (int i = 0; i < 4; i++) {
    int ny = cy + dy[i];
    int nx = cx + dx[i];
    if (ny >= 0 && nx >= 0 && ny < H && nx < W && !used[ny][nx] &&
        field[ny][nx] == 'X')
      cnt += labelling(ny, nx, k);
  }
  return cnt;
}

int main() {
  while (cin >> W >> H && (H | W)) {
    for (int i = 0; i < H; i++) {
      for (int j = 0; j < W; j++) {
        cin >> field[i][j];
        if (field[i][j] == 'S') {
          sy = i;
          sx = j;
          field[i][j] = '.';
        } else if (field[i][j] == 'G') {
          gy = i;
          gx = j;
          field[i][j] = '.';
        }
      }
    }
    ice = 0;
    memset(used, 0, sizeof(used));
    memset(iceNumber, -1, sizeof(iceNumber));
    for (int i = 0; i < H; i++)
      for (int j = 0; j < W; j++)
        if (!used[i][j] && field[i][j] == 'X') {
          tileNum[ice] = labelling(i, j, ice);
          ice++;
        }
    bfs();
    int res = astar();
    cout << res << endl;
  }

  return 0;
}

Fixed submission:
#include <algorithm>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <vector>

using namespace std;
typedef pair<int, int> pii;
int H, W;
int sy, sx, gy, gx;
char field[101][101];
int ice;
int iceNumber[101][101];
// iceごとのタイル数
int tileNum[101];
bool used[101][101];
const int dy[] = {-1, 0, 0, 1};
const int dx[] = {0, -1, 1, 0};
int predic[101][101];

// 状態に必要なもの
// ここまでのコスト
// どのiceを何度踏んだか(vectorでもつ)
typedef pair<pii, vector<int>> Info;
typedef pair<int, pair<pii, vector<int>>> Sit;

// 氷を踏む回数を無視したときのgoalからの最短距離
void bfs() {
  queue<pii> q;
  memset(predic, -1, sizeof(predic));
  q.push(pii(gy, gx));
  predic[gy][gx] = 0;
  while (q.size()) {
    pii p = q.front();
    q.pop();
    int cy = p.first;
    int cx = p.second;
    int ccost = predic[cy][cx];
    for (int i = 0; i < 4; i++) {
      int ny = cy + dy[i];
      int nx = cx + dx[i];
      if (ny >= 0 && nx >= 0 && ny < H && nx < W && predic[ny][nx] == -1 &&
          field[ny][nx] != '#') {
        int ncost = ccost + 1;
        predic[ny][nx] = ncost;
        q.push(pii(ny, nx));
      }
    }
  }
}

int astar() {
  priority_queue<Sit, vector<Sit>, greater<Sit>> pq;
  map<Info, int> d;
  vector<int> sv(ice, 0);
  d[(make_pair(pii(sy, sx), sv))] = predic[sy][sx];
  pq.push(Sit(predic[sy][sx], make_pair(pii(sy, sx), sv)));
  int res = 10000000;
  while (pq.size()) {
    Sit p = pq.top();
    pq.pop();
    int cy = p.second.first.first;
    int cx = p.second.first.second;
    int ccost = p.first;
    vector<int> ctile = p.second.second;
    if (d.count(p.second) > 0 && ccost > d[p.second])
      continue;
    int realCost = ccost - predic[cy][cx];
    if (cy == gy && cx == gx)
      return realCost;
    for (int i = 0; i < 4; i++) {
      int ny = cy + dy[i];
      int nx = cx + dx[i];
      if (ny >= 0 && nx >= 0 && ny < H && nx < W && field[ny][nx] != '#') {
        vector<int> ntile = ctile;
        int ncost = (realCost + 1) + predic[ny][nx];
        Info ninfo = p.second;
        ninfo.first.first = ny;
        ninfo.first.second = nx;
        if (field[ny][nx] == 'X') {
          int a = iceNumber[ny][nx];
          ninfo.second[a]++;
          if (ninfo.second[a] > tileNum[a] / 2)
            continue;
        }
        if (d.count(ninfo) == 0 || d[ninfo] > ncost) {
          d[ninfo] = ncost;
          pq.push(make_pair(ncost, ninfo));
          if (gy == ny && gx == nx)
            res = min(res, ncost);
        }
      }
    }
  }
  return res;
}

int labelling(int cy, int cx, int k) {
  int cnt = 1;
  used[cy][cx] = true;
  iceNumber[cy][cx] = k;
  for (int i = 0; i < 4; i++) {
    int ny = cy + dy[i];
    int nx = cx + dx[i];
    if (ny >= 0 && nx >= 0 && ny < H && nx < W && !used[ny][nx] &&
        field[ny][nx] == 'X')
      cnt += labelling(ny, nx, k);
  }
  return cnt;
}

int main() {
  while (cin >> W >> H && (H | W)) {
    for (int i = 0; i < H; i++) {
      for (int j = 0; j < W; j++) {
        cin >> field[i][j];
        if (field[i][j] == 'S') {
          sy = i;
          sx = j;
          field[i][j] = '.';
        } else if (field[i][j] == 'G') {
          gy = i;
          gx = j;
          field[i][j] = '.';
        }
      }
    }
    ice = 0;
    memset(used, 0, sizeof(used));
    memset(iceNumber, -1, sizeof(iceNumber));
    for (int i = 0; i < H; i++)
      for (int j = 0; j < W; j++)
        if (!used[i][j] && field[i][j] == 'X') {
          tileNum[ice] = labelling(i, j, ice);
          ice++;
        }
    bfs();
    int res = astar();
    cout << res << endl;
  }

  return 0;
}