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

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <vector>

using namespace std;

#define MAX_H 12
#define MAX_W 12
#define INF (1 << 28)
int h, w;
int F[MAX_H][MAX_W];

bool dfs_used[MAX_H][MAX_W];
const int dy[] = {0, 1, 0, -1}, dx[] = {1, 0, -1, 0};
int dfs(int y, int x, int n) {
  F[y][x] = n;
  int cnt = 1;
  for (int i = 0; i < 4; i++) {
    int ny = y + dy[i], nx = x + dx[i];
    if (0 <= ny && ny < h && 0 <= nx && nx < w && !dfs_used[ny][nx] &&
        F[ny][nx] == INF)
      cnt += dfs(ny, nx, n);
  }
  return cnt;
}

int ice_count[MAX_H * MAX_W];
int ice_lump_count;
int dist_from_goal[MAX_H][MAX_W];
struct S {
  int y, x, t;
  S(int y, int x, int t) : y(y), x(x), t(t) {}
};

int sy, sx, gy, gx;
void init() {
  memset(dfs_used, 0, sizeof(dfs_used));
  memset(ice_count, 0, sizeof(ice_count));
  memset(dist_from_goal, -1, sizeof(dist_from_goal));
  int n = 1;
  for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
      if (F[i][j] == INF) {
        ice_count[n] = dfs(i, j, n);
        n++;
      }
    }
  }
  ice_lump_count = n;

  // 各タイルに対しbfsで氷を考慮しない場合のゴールまでの最短距離を求める.
  queue<S> q;
  q.push(S(gy, gx, 0));
  dist_from_goal[gy][gx] = 0;
  while (!q.empty()) {
    S p = q.front();
    q.pop();
    for (int i = 0; i < 4; i++) {
      int ny = p.y + dy[i], nx = p.x + dx[i];
      if (0 <= ny && ny < h && 0 <= nx && nx < w &&
          dist_from_goal[ny][nx] < 0 && F[ny][nx] >= 0) {
        dist_from_goal[ny][nx] = p.t + 1;
        q.push(S(ny, nx, p.t + 1));
      }
    }
  }
}

bool dls_used[MAX_H][MAX_W];
bool __used[MAX_H][MAX_W];
int count_used_ice(int y, int x) {
  int cnt = (dls_used[y][x] ? 1 : 0);
  // if (cnt == 1) cout << "count_used_ice: " << y << ',' << x << endl;
  for (int i = 0; i < 4; i++) {
    int ny = y + dy[i], nx = x + dx[i];
    if (0 <= ny && ny < h && 0 <= nx && nx < w && !__used[ny][nx] &&
        F[ny][nx] == F[y][x]) {
      __used[ny][nx] = true;
      cnt += count_used_ice(ny, nx);
    }
  }
  return cnt;
}

bool ice_break(int y, int x) {
  memset(__used, 0, sizeof(__used));
  __used[y][x] = true;
  int c = count_used_ice(y, x);
  // cout << "icebreak: " << c << endl;
  return c * 2 > ice_count[F[y][x]];
}

bool dls(int y, int x, int depth) {
  // cout << y << ',' << x << ',' << depth << endl;
  if (depth == 0)
    return y == gy && x == gx;
  if (dist_from_goal[y][x] > depth)
    return false;
  for (int i = 0; i < 4; i++) {
    int ny = y + dy[i];
    int nx = x + dx[i];
    if (0 <= ny && ny < h && 0 <= nx && nx < w && !dls_used[ny][nx] &&
        F[ny][nx] >= 0) {
      dls_used[ny][nx] = true;
      if (F[ny][nx] > 0)
        if (ice_break(ny, nx)) {
          dls_used[ny][nx] = false;
          continue;
        }
      if (dls(ny, nx, depth - 1)) {
        // cout << endl;
        // for (int k = 0; k < h; k++) {
        //     for (int l = 0; l < w; l++)
        //         cout << dls_used[k][l] << ' ';
        //     cout << endl;
        // }
        dls_used[ny][nx] = false;
        return true;
      }
      dls_used[ny][nx] = false;
    }
  }
  return false;
}

int iddfs() {
  int depth = 0;
  int y = sy, x = sx;
  while (true) {
    memset(dls_used, 0, sizeof(dls_used));
    dls_used[y][x] = true;
    if (dls(y, x, depth))
      return depth;
    depth++;
  }
}

void debug() {
  printf("Ice lump count: %d\\n", ice_lump_count);
  printf("Ice count: %d\\n\\t", ice_lump_count);
  for (int i = 0; i < ice_lump_count; i++)
    printf("%3d ", ice_count[i]);
  printf("\\n");
  for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
      printf("%4d ", F[i][j]);
    }
    printf("\\n");
  }
  for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
      printf("%4d ", dist_from_goal[i][j]);
    }
    printf("\\n");
  }
}

int main() {
  while (cin >> w >> h, w || h) {
    for (int i = 0; i < h; i++) {
      for (int j = 0; j < w; j++) {
        char t;
        cin >> t;
        switch (t) {
        case 'S':
          sy = i, sx = j;
          F[i][j] = 0;
          break;
        case 'G':
          gy = i, gx = j;
          F[i][j] = 0;
          break;
        case '.':
          F[i][j] = 0;
          break;
        case '#':
          F[i][j] = -1;
          break;
        case 'X':
          F[i][j] = INF;
          break;
        }
      }
    }
    init();
    // debug();
    cout << iddfs() << endl;
  }
  return 0;
}

Error: MLE

Fixed submission:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <vector>

using namespace std;

#define MAX_H 12
#define MAX_W 12
#define INF (1 << 28)
int h, w;
int F[MAX_H][MAX_W];

bool dfs_used[MAX_H][MAX_W];
const int dy[] = {0, 1, 0, -1}, dx[] = {1, 0, -1, 0};
int dfs(int y, int x, int n) {
  F[y][x] = n;
  int cnt = 1;
  for (int i = 0; i < 4; i++) {
    int ny = y + dy[i], nx = x + dx[i];
    if (0 <= ny && ny < h && 0 <= nx && nx < w && !dfs_used[ny][nx] &&
        F[ny][nx] == INF)
      cnt += dfs(ny, nx, n);
  }
  return cnt;
}

int ice_count[MAX_H * MAX_W];
int ice_lump_count;
void init() {
  memset(dfs_used, 0, sizeof(dfs_used));
  memset(ice_count, 0, sizeof(ice_count));
  int n = 1;
  for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
      if (F[i][j] == INF) {
        ice_count[n] = dfs(i, j, n);
        n++;
      }
    }
  }
  ice_lump_count = n;
}

int sy, sx, gy, gx;

struct S {
  int y, x;
  int t;
  vector<int> used_ice;
  S() {}
  S(int y, int x, vector<int> used_ice, int t)
      : y(y), x(x), used_ice(used_ice), t(t) {}
};

int bfs() {
  map<vector<int>, bool> bfs_used[MAX_H][MAX_W];
  queue<S> q;
  vector<int> initial_used_ice(ice_lump_count + 1, 0);
  q.push(S(sy, sx, initial_used_ice, 0));
  bfs_used[sy][sx][initial_used_ice] = true;
  while (!q.empty()) {
    S p = q.front();
    q.pop();
    int y = p.y, x = p.x;
    int t = p.t;
    if (y == gy && x == gx)
      return t;
    // printf("in bfs, y: %d, x: %d, t: %d", y, x, t);
    // printf("    used: ");
    // for (int i = 1; i < ice_lump_count; i++) printf("%3d ", p.used_ice[i]);
    // printf("\\n");
    for (int i = 0; i < 4; i++) {
      int ny = y + dy[i], nx = x + dx[i];
      if (0 <= ny && ny < h && 0 <= nx && nx < w &&
          !bfs_used[ny][nx][p.used_ice] && F[ny][nx] >= 0) {
        vector<int> used_ice = p.used_ice;
        if (F[ny][nx] > 0) {
          int c = F[ny][nx];
          used_ice[c]++;
          if (used_ice[c] * 2 > ice_count[c])
            continue;
        }
        bfs_used[ny][nx][used_ice] = true;
        q.push(S(ny, nx, used_ice, t + 1));
      }
    }
  }
  return INF;
}

void debug() {
  printf("Ice lump count: %d\\n", ice_lump_count);
  printf("Ice count: %d\\n\\t", ice_lump_count);
  for (int i = 0; i < ice_lump_count; i++)
    printf("%3d ", ice_count[i]);
  printf("\\n");
  for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
      printf("%4d ", F[i][j]);
    }
    printf("\\n");
  }
}

int main() {
  while (cin >> w >> h, w || h) {
    for (int i = 0; i < h; i++) {
      for (int j = 0; j < w; j++) {
        char t;
        cin >> t;
        switch (t) {
        case 'S':
          sy = i, sx = j;
          F[i][j] = 0;
          break;
        case 'G':
          gy = i, gx = j;
          F[i][j] = 0;
          break;
        case '.':
          F[i][j] = 0;
          break;
        case '#':
          F[i][j] = -1;
          break;
        case 'X':
          F[i][j] = INF;
          break;
        }
      }
    }
    init();
    // debug();
    cout << bfs() << endl;
  }
  return 0;
}