Problem p00247 (C++) — buggy submission, verdict: Memory Limit Exceeded

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

typedef pair<int, int> P;
const int MAX_W = 12;
const int INF = 1e+8;

int w, h;
vector<string> s;
int dx[4] = {0, 0, -1, 1};
int dy[4] = {-1, 1, 0, 0};
// ice[y][x] := 氷の番号を返す. (連結な氷をひとつのまとまりとする)
int ice[MAX_W][MAX_W];
// g[y][x] := (x,y) からゴールへの仮の距離
int g[MAX_W][MAX_W];

// (コスト,スタートからの距離,位置,氷の耐久)
struct State {
  int cost, cnt, x, y;
  vector<int> b;
  State(int cost_, int cnt_, int x_, int y_, const vector<int> &b_) {
    cost = cost_;
    cnt = cnt_;
    x = x_;
    y = y_;
    b = b_;
  }
};
bool operator<(const State &a, const State &b) { return a.cost > b.cost; }

// 氷の連結成分を調べる.
void dfs(int x, int y, vector<P> &vp) {
  if (s[y][x] == 'X') {
    s[y][x] = 'x';
    vp.push_back(P(x, y));
  } else {
    return;
  }
  for (int i = 0; i < 4; i++) {
    int mx = x + dx[i];
    int my = y + dy[i];
    if (mx < 0 || my < 0 || w <= mx || h <= my)
      continue;
    if (s[my][mx] == 'X') {
      dfs(mx, my, vp);
    }
  }
}

// ゴールからの仮の距離を調べる
void bfs(int gx, int gy) {
  queue<P> q;
  q.push(P(gx, gy));
  g[gy][gx] = 0;
  while (!q.empty()) {
    int x = q.front().first;
    int y = q.front().second;
    int cnt = g[y][x];
    q.pop();

    for (int i = 0; i < 4; i++) {
      int mx = x + dx[i];
      int my = y + dy[i];
      if (mx < 0 || my < 0 || w <= mx || h <= my)
        continue;
      if (s[my][mx] == '.' || s[my][mx] == 'x') {
        if (g[my][mx] == INF) {
          g[my][mx] = cnt + 1;
          q.push(P(mx, my));
        }
      }
    }
  }
}

int solve() {
  int sx, sy, gx, gy;
  int memo[MAX_W][MAX_W];
  // 初期化
  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
      ice[y][x] = -1;
      g[y][x] = INF;
      memo[y][x] = 0;
    }
  }
  // b[id] := 氷の番号 id があと何歩で壊れるかを返す.
  vector<int> b;
  // スタートとゴールと氷の連結成分を調べる.
  int id = 0;
  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
      if (s[y][x] == 'S') {
        s[y][x] = '.';
        sx = x;
        sy = y;
      }
      if (s[y][x] == 'G') {
        s[y][x] = '.';
        gx = x;
        gy = y;
      }
      if (s[y][x] == 'X') {
        vector<P> vp;
        dfs(x, y, vp);
        for (int i = 0; i < vp.size(); i++) {
          int ax = vp[i].first;
          int ay = vp[i].second;
          ice[ay][ax] = id;
        }
        b.push_back(vp.size() / 2);
        id++;
      }
    }
  }
  // ゴールからの仮の距離を調べる
  bfs(gx, gy);

  // (コスト,スタートからの距離,位置) を優先度つきキューで保持
  // コストは スタートからの距離 + ゴールまでの仮の距離
  priority_queue<State> q;
  q.push(State(g[sy][sx], 0, sx, sy, b));

  int res = INF;
  while (!q.empty()) {
    int cost = q.top().cost;
    int cnt = q.top().cnt;
    int x = q.top().x;
    int y = q.top().y;
    vector<int> b = q.top().b;
    q.pop();
    memo[y][x]++;
    if (memo[y][x] > 100)
      continue;

    if (res < cnt + g[y][x])
      continue;
    if (x == gx && y == gy) {
      res = min(res, cnt);
      continue;
    }
    for (int i = 0; i < 4; i++) {
      int mx = x + dx[i];
      int my = y + dy[i];
      if (mx < 0 || my < 0 || w <= mx || h <= my)
        continue;
      if (s[my][mx] == '.') {
        q.push(State(cnt + g[my][mx], cnt + 1, mx, my, b));
      }
      if (s[my][mx] == 'x') {
        int id = ice[my][mx];
        if (id < b.size() && b[id] > 0) {
          b[id]--;
          q.push(State(cnt + g[my][mx], cnt + 1, mx, my, b));
          b[id]++;
        }
      }
    }
  }
  return res;
}

int main() {
  while (cin >> w >> h, w || h) {
    s = vector<string>(h);
    for (int y = 0; y < h; y++) {
      cin >> s[y];
    }
    int ans = solve();
    cout << ans << endl;
  }
}

Error: MLE

Fixed submission:

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

typedef pair<char, char> P;
typedef pair<P, vector<int>> State;
const int MAX_W = 12;
const int INF = 1e+8;

int w, h;
vector<string> s;
int dx[4] = {0, 0, -1, 1};
int dy[4] = {-1, 1, 0, 0};
// ice[y][x] := 氷の番号を返す. (連結な氷をひとつのまとまりとする)
int ice[MAX_W][MAX_W];

// 氷の連結成分を調べる.
void dfs(int x, int y, vector<P> &vp) {
  if (s[y][x] == 'X') {
    s[y][x] = 'x';
    vp.push_back(P(x, y));
  } else {
    return;
  }
  for (int i = 0; i < 4; i++) {
    int mx = x + dx[i];
    int my = y + dy[i];
    if (mx < 0 || my < 0 || w <= mx || h <= my)
      continue;
    if (s[my][mx] == 'X') {
      dfs(mx, my, vp);
    }
  }
}

int solve() {
  int sx, sy, gx, gy;
  // 初期化
  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
      ice[y][x] = -1;
    }
  }
  // b[id] := 氷の番号 id があと何歩で壊れるかを返す.
  vector<int> b;
  // スタートとゴールと氷の連結成分を調べる.
  int id = 0;
  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
      if (s[y][x] == 'S') {
        s[y][x] = '.';
        sx = x;
        sy = y;
      }
      if (s[y][x] == 'G') {
        s[y][x] = '.';
        gx = x;
        gy = y;
      }
      if (s[y][x] == 'X') {
        vector<P> vp;
        dfs(x, y, vp);
        for (int i = 0; i < vp.size(); i++) {
          int ax = vp[i].first;
          int ay = vp[i].second;
          ice[ay][ax] = id;
        }
        b.push_back(vp.size() / 2);
        id++;
      }
    }
  }
  map<State, int> d;
  d[State(P(sx, sy), b)] = 0;
  queue<State> q;
  q.push(State(P(sx, sy), b));
  int res = INF;
  while (!q.empty()) {
    int x = q.front().first.first;
    int y = q.front().first.second;
    vector<int> b = q.front().second;
    int cnt = d[State(P(x, y), b)];
    q.pop();

    if (x == gx && y == gy) {
      res = cnt;
      break;
    }
    for (int i = 0; i < 4; i++) {
      int mx = x + dx[i];
      int my = y + dy[i];
      if (mx < 0 || my < 0 || w <= mx || h <= my)
        continue;
      if (s[my][mx] == '.') {
        State next(P(mx, my), b);
        if (!d.count(next)) {
          d[next] = cnt + 1;
          q.push(next);
        }
      }
      if (s[my][mx] == 'x') {
        int id = ice[my][mx];
        if (id < b.size() && b[id] > 0) {
          b[id]--;
          State next(P(mx, my), b);
          if (!d.count(next)) {
            d[next] = cnt + 1;
            q.push(next);
          }
          b[id]++;
        }
      }
    }
  }
  return res;
}

int main() {
  while (cin >> w >> h, w || h) {
    s = vector<string>(h);
    for (int y = 0; y < h; y++) {
      cin >> s[y];
    }
    int ans = solve();
    cout << ans << endl;
  }
}