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

#include <algorithm>
#include <cassert>
#include <climits>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <queue>
#include <vector>

#define REP(i, s, n) for (int i = s; i < n; i++)
#define rep(i, n) REP(i, 0, n)
#define inf (1 << 28)
#define MAX 51
using namespace std;
int h, w;
string G[MAX];
int mincost[MAX * MAX][4][4];
int dx[] = {+0, +1, +0, -1}; //&#9757;↑→↓←
int dy[] = {-1, +0, +1, +0};
int kdx[] = {0, 1, 1, 0};
int kdy[] = {0, 0, 1, 1};

/*

o <- od
2 <- d2
   o2
  2KKo
  oKK2
   2o

 */
int dx2[] = {+1, +0, -1, +0};
int dy2[] = {+0, +1, +0, -1};

int odx[] = {+0, +2, +1, -1};
int ody[] = {-1, +0, +2, +1};

struct P {
  int x, y;
  P(int x = -1, int y = -1) : x(x), y(y) {}
};

struct Pox {
  P p;
  int cost;
  Pox(P p = P(), int cost = -1) : p(p), cost(cost) {}
  bool operator<(const Pox &a) const { return cost > a.cost; }
};

struct Pess {
  P p;
  int cost;
  int dir;
  Pess(P p = P(), int cost = -1, int dir = -1) : p(p), cost(cost), dir(dir) {}
  bool operator<(const Pess &a) const { return cost > a.cost; }
};

inline int getIndex(P p) { return p.x + p.y * w; }

int open_mincost[MAX * MAX];

void open_the_door(P pxl,
                   P king) // do not move the king before using this function
{

  priority_queue<Pox> Q;
  Q.push(Pox(pxl, 0));
  bool used[MAX * MAX];
  bool in_king[MAX * MAX];
  rep(i, MAX * MAX) open_mincost[i] = inf, used[i] = false, in_king[i] = false;
  open_mincost[getIndex(pxl)] = 0;
  int cnt = 0;
  rep(i, 4) {
    int kx = king.x + kdx[i];
    int ky = king.y + kdy[i];

    if (!(0 <= kx && kx < w && 0 <= ky && ky < h)) {
      // cout << "XXXXX error XXXXX" << endl;
      // cout << kx << "," << ky << " are out of the range" << endl;
      assert(false);
    }
    // cout << "king : " << kx << "," << ky << " = " << getIndex(P(kx,ky))<<
    // endl;
    in_king[getIndex(P(kx, ky))] = true;
  }

  rep(i, 4) {
    int x1 = king.x + odx[i];
    int y1 = king.y + ody[i];
    if (0 <= x1 && x1 < w && 0 <= y1 && y1 < h && G[y1][x1] != '*') {
      // cout << "add " << x1 << "," << y1 << endl;
      used[getIndex(P(x1, y1))] = true;
      cnt++;
    }
    int x2 = x1 + dx2[i];
    int y2 = y1 + dy2[i];
    if (0 <= x2 && x2 < w && 0 <= y2 && y2 < h && G[y2][x2] != '*') {
      // cout << "add " << x2 << "," << y2 << endl;
      used[getIndex(P(x2, y2))] = true;
      cnt++;
    }
  }
  // cout << "cnt = " << cnt << endl;
  while (!Q.empty()) {
    Pox pox = Q.top();
    Q.pop();
    if (used[getIndex(pox.p)]) {
      // cout <<"here "<< pox.p.x << "," << pox.p.y << endl;
      used[getIndex(pox.p)] = false;
      cnt--;
    }
    if (cnt <= 0)
      return;

    rep(i, 4) {
      int nx = pox.p.x + dx[i];
      int ny = pox.p.y + dy[i];
      // cout << "from" << pox.p.x << "," << pox.p.y << " want to go to " << nx
      // << "," << ny << endl;
      if (!(0 <= nx && nx < w && 0 <= ny && ny < h))
        continue;
      // cout << "---1" << endl;
      if (G[ny][nx] == '*')
        continue;
      // cout << "---3 " << nx << "," << ny << " " <<
      // in_king[getIndex(P(nx,ny))] << endl;
      if (in_king[getIndex(P(nx, ny))])
        continue;
      // cout << "---4" << endl;
      // cout << "now : " << open_mincost[getIndex(P(nx,ny))] << " >? "<<
      // pox.cost+1 << endl;
      if (open_mincost[getIndex(P(nx, ny))] > pox.cost + 1) {
        // cout << "goto " << nx << "," << ny  << " : cost = " << pox.cost+1<<
        // endl; assert(!(nx == 3 && ny == 2));
        open_mincost[getIndex(P(nx, ny))] = pox.cost + 1;
        Q.push(Pox(P(nx, ny), pox.cost + 1));
      }
    }
  }
}

void init_mincost() {
  int temp[4][2];
  rep(i, MAX * MAX) rep(j, 4) rep(k, 4) mincost[i][j][k] = inf;

  rep(i, h) {
    if (i + 1 >= h)
      continue;
    rep(j, w) {
      if (G[i][j] == '*')
        continue;
      if (j + 1 >= w)
        continue;
      rep(k, 4) {
        int nx = j + odx[k];
        int ny = i + ody[k];
        if (!(0 <= nx && nx < w && 0 <= ny && ny < h))
          continue;
        if (G[ny][nx] == '*')
          continue;

        int mx = nx + dx2[k];
        int my = ny + dy2[k];
        if (!(0 <= mx && mx < w && 0 <= my && my < h))
          continue;
        if (G[my][mx] == '*')
          continue;

        open_the_door(
            P(nx, ny),
            P(j, i)); // calculate the minimum cost from P(nx,ny) to all cells
        rep(l, 4) {   // store the information about the minimum cost from
                    // P(nx,ny)
          int x1 = j + odx[l];
          int y1 = i + ody[l];
          if (!(0 <= x1 && x1 < w && 0 <= y1 && y1 < h) || G[y1][x1] == '*') {
            temp[l][0] = temp[l][1] = inf;
            continue;
          }
          int x2 = x1 + dx2[l];
          int y2 = y1 + dy2[l];
          if (!(0 <= x2 && x2 < w && 0 <= y2 && y2 < h) || G[y2][x2] == '*') {
            temp[l][0] = temp[l][1] = inf;
            continue;
          }
          temp[l][0] = open_mincost[getIndex(P(x1, y1))];
          temp[l][1] = open_mincost[getIndex(P(x2, y2))];
        }
        /*
            if(j == 4 && i == 2 && k == 2)
              {
                cout << "origine!" << endl;
                cout << temp[3][0] << " " << temp[3][1] << endl;
              }
        */
        open_the_door(
            P(mx, my),
            P(j, i)); // caluclate the minimum cost from P(mx,my) to all cells

        rep(l, 4) {
          int x1 = j + odx[l];
          int y1 = i + ody[l];
          if (!(0 <= x1 && x1 < w && 0 <= y1 && y1 < h) || G[y1][x1] == '*') {
            continue;
          }
          int x2 = x1 + dx2[l];
          int y2 = y1 + dy2[l];
          if (!(0 <= x2 && x2 < w && 0 <= y2 && y2 < h) || G[y2][x2] == '*') {
            continue;
          }
          mincost[getIndex(P(j, i))][k][l] =
              min(temp[l][0] + open_mincost[getIndex(P(x2, y2))],
                  temp[l][1] + open_mincost[getIndex(P(x1, y1))]);

          if (k == l) {
            assert(mincost[getIndex(P(j, i))][k][l] == 0);
          }
        }

        /*
            if(j == 4 && i == 2 && k == 2)
              {
                cout << "habeii!" << endl;
                cout << mincost[getIndex(P(4,2))][2][3] << endl;
              }
        */
      }
    }
  }
}

/* collisionする場合ってありえる？
->そもそも関係ない気がする！！！
XXXXXXX
      X
XXXXX↓X
   →collision!!!
XXXXX
XXXXXXXXXXXX.................................................
.....XXXXXXX......................................
.XXX.....XXXX.....................................
...XXXXX....X.....................................
KK.....X.XX.X.....................................
KKXXXX...X........................................
..X..XXXXX........................................
.....XXXXX........................................
..................................................
 */

int King_Of_The_King[4]; //&#9757;上、右、下、左

bool check(int x, int y) {
  // cout << "isok? " << x << "," << y << " ";
  rep(i, 4) {
    int kx = x + kdx[i];
    int ky = y + kdy[i];
    if (!(0 <= kx && kx < w && 0 <= ky && ky < h)) {
      // cout << "NO!" << endl;
      return false;
    }
    if (G[ky][kx] == '*') {
      // cout << "NO!!" << endl;
      return false;
    }
  }
  // cout << " oK!" << endl;
  return true;
}

int costc[MAX * MAX][4];
void dijkstra(P king) {
  priority_queue<Pess> Q;
  rep(i, 4) Q.push(Pess(king, King_Of_The_King[i], i));

  rep(i, MAX * MAX) rep(j, 4) costc[i][j] = inf;
  rep(i, 4) costc[getIndex(king)][i] = King_Of_The_King[i];

  while (!Q.empty()) {
    Pess pess = Q.top();
    Q.pop();
    // cout << "------------- " << pess.p.x << "," << pess.p.y << endl;
    if (pess.p.x == 0 && pess.p.y == 0) {
      cout << pess.cost << endl;
      return;
    }
    rep(i, 4) {
      int nx = pess.p.x + dx[i];
      int ny = pess.p.y + dy[i];
      if (!check(nx, ny))
        continue;
      // cout << "to " << nx << "," << ny << "  " <<
      // costc[getIndex(P(nx,ny))][(i+2)%2] << " > " << pess.cost << "+" <<
      // mincost[getIndex(pess.p)][pess.dir][i]+1 << " mincost["<<pess.p.x <<
      // ","<< pess.p.y<<"]["<<pess.dir<<"]["<<i<<"]"<< endl;
      if (costc[getIndex(P(nx, ny))][(i + 2) % 2] >
          pess.cost + mincost[getIndex(pess.p)][pess.dir][i] + 1) {
        // cout << "from " << pess.p.x << "," << pess.p.y << " to " << nx << ","
        // << ny << endl;
        costc[getIndex(P(nx, ny))][(i + 2) % 2] =
            pess.cost + mincost[getIndex(pess.p)][pess.dir][i] + 1;
        Q.push(Pess(P(nx, ny),
                    pess.cost + mincost[getIndex(pess.p)][pess.dir][i] + 1,
                    (i + 2) % 4));
      }
    }
  }
  cout << -1 << endl;
}

// its time to play the game
void move_open_to_the_side_of_King(P o1, P o2, P king) {
  int temp[4][2];

  open_the_door(o1, king);
  rep(i, 4) {
    int x1 = king.x + odx[i];
    int y1 = king.y + ody[i];
    if (!(0 <= x1 && x1 < w && 0 <= y1 && y1 < h) || G[y1][x1] == '*') {
      // temp[i][0] = temp[i][1] = inf;
      temp[i][0] = temp[i][1] = 0;
      continue;
    }
    int x2 = x1 + dx2[i];
    int y2 = y1 + dy2[i];
    if (!(0 <= x2 && x2 < w && 0 <= y2 && y2 < h) || G[y2][x2] == '*') {
      // temp[i][0] = temp[i][1] = inf;
      temp[i][0] = temp[i][1] = 0;
      continue;
    }
    temp[i][0] = open_mincost[getIndex(P(x1, y1))];
    temp[i][1] = open_mincost[getIndex(P(x2, y2))];
  }

  open_the_door(o2, king);
  rep(i, 4) {
    int x1 = king.x + odx[i];
    int y1 = king.y + ody[i];
    if (!(0 <= x1 && x1 < w && 0 <= y1 && y1 < h) || G[y1][x1] == '*') {
      // King_Of_The_King[i] = inf;
      King_Of_The_King[i] = 0;
      continue;
    }
    int x2 = x1 + dx2[i];
    int y2 = y1 + dy2[i];
    if (!(0 <= x2 && x2 < w && 0 <= y2 && y2 < h) || G[y2][x2] == '*') {
      // King_Of_The_King[i] = inf;
      King_Of_The_King[i] = 0;
      continue;
    }

    // cout << temp[i][0] << "," << temp[i][1] << " " <<
    // open_mincost[getIndex(P(x2,y2))] << "," <<
    // open_mincost[getIndex(P(x1,y1))] << endl;
    King_Of_The_King[i] = min(temp[i][0] + open_mincost[getIndex(P(x2, y2))],
                              temp[i][1] + open_mincost[getIndex(P(x1, y1))]);
  }
}

int main() {
  // clock_t st,ed;
  // st = clock();
  while (cin >> h >> w, h | w) {

    vector<P> open;
    P king;

    rep(i, h) {
      cin >> G[i];
      rep(j, w) {
        if (G[i][j] == '.')
          open.push_back(P(j, i));

        if (G[i][j] == 'X' && king.x == -1 && king.y == -1)
          king = P(j, i);
      }
    }

    if (king.x == 0 && king.y == 0) {
      cout << 0 << endl;
      continue;
    }

    init_mincost();
    move_open_to_the_side_of_King(open[0], open[1], king);
    dijkstra(king);
    // move_open_to_the_side_of_King(open[0],open[1],king);
    // cout << King_Of_The_King[0] << endl;
    // cout << King_Of_The_King[1] << endl;
    // cout << King_Of_The_King[2] << endl;
    // cout << King_Of_The_King[3] << endl;

    // open_the_door(P(4,4),P(4,2));

    // cout << open_mincost[getIndex(P(3,2))] << endl;
    // cout << open_mincost[getIndex(P(3,3))] << endl;
    /*
    init_mincost();
    int cnt = 1;
    rep(i,h)
    {
    rep(j,w)
    {
      //cout << "from " << j << " " << i << endl;
    rep(k,4)
    {
    rep(l,4)
    {
      if(cnt == 113)
        {
          cout << i << " " << j << " " << k << " " << l << endl;
        }
      cnt++;
      if(mincost[j+i*w][k][l] >= inf)cout << 0 << endl;
      else cout << mincost[j+i*w][k][l]+1 << endl;
    }
    }
    }
    }
    */
    // cout << mincost[getIndex(P(3,3))][0][2] << endl;
  }
  // ed = clock();
  // cout << setiosflags(ios::fixed) << setprecision(10) <<
  // (double)(ed-st)/CLOCKS_PER_SEC << endl;
  return 0;
}

Error: MLE

Fixed submission:

#include <algorithm>
#include <cassert>
#include <climits>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <vector>
#define inf (1 << 29)
#define REP(i, s, n) for (int i = s; i < n; i++)
#define rep(i, n) REP(i, 0, n)
#define all(n) (n).begin(), (n).end()
#define MAX 251
using namespace std;
typedef pair<int, int> ii;
typedef pair<ii, int> iii;
int h, w;
string G[51];
// int mincost[MAX][MAX][MAX];//mincost[open1][open2][king] := the minimum cost
map<iii, bool> mincost;

int dx[] = {0, 1, 0, -1}; // 下、右、上、左
int dy[] = {1, 0, -1, 0};
int kdx[] = {0, 1, 0, 1};
int kdy[] = {0, 0, 1, 1};
int sdx[] = {};
int sdy[] = {};

struct Point {
  int x, y;
  Point(int x = -1, int y = -1) : x(x), y(y) {}
  bool operator<(const Point &a) const {
    if (x != a.x)
      return x < a.x;
    return y < a.y;
  }
};

struct State {
  Point king;
  Point op[2];
  int cost;
  State(Point king, Point op1, Point op2, int cost = -1)
      : king(king), cost(cost) {
    op[0] = op1, op[1] = op2;
  }
  bool operator<(const State &a) const { return cost > a.cost; }
};

int toIndex(Point p) { return p.x + p.y * w; }

void trace(Point p1, Point p2, Point p3) {
  rep(i, h) {
    rep(j, w) {
      if (G[i][j] == '*') {
        cout << G[i][j];
        continue;
      }
      if (p1.x == j && p1.y == i) {
        cout << '.';
        continue;
      }
      if (p2.x == j && p2.y == i) {
        cout << '.';
        continue;
      }

      bool check_king = true;
      rep(k, 4) {
        int nx = p3.x + kdx[k];
        int ny = p3.y + kdy[k];
        if (nx == j && ny == i) {
          cout << 'X';
          check_king = false;
          continue;
        }
      }
      if (!check_king)
        continue;
      cout << 'o';
    }
    cout << endl;
  }
  cout << endl << endl;
}

bool slide_check(int dir, Point &p1, Point &p2, Point king) {
  map<Point, bool> exist;
  exist[p1] = true;
  exist[p2] = true;
  rep(i, 4) {
    int nx = king.x + kdx[i];
    int ny = king.y + kdy[i];
    if (!(0 <= nx && nx < w && 0 <= ny && ny < h))
      return false;
    if (G[ny][nx] == '*')
      return false;
  }
  // 下、右、上、左
  Point pp1, pp2;
  if (dir == 0) {
    // 0,  1, 2,   3
    // 今、右、下、斜め
    pp1 = Point(king.x + kdx[2], king.y + kdy[2]);
    pp2 = Point(king.x + kdx[3], king.y + kdy[3]);
    p1 = Point(king.x, king.y - 1);
    p2 = Point(king.x + 1, king.y - 1);
  }
  if (dir == 1) {
    pp1 = Point(king.x + kdx[1], king.y + kdy[1]);
    pp2 = Point(king.x + kdx[3], king.y + kdy[3]);
    p1 = Point(king.x - 1, king.y);
    p2 = Point(king.x - 1, king.y + 1);
  }
  if (dir == 2) {
    pp1 = Point(king.x + kdx[0], king.y + kdy[0]);
    pp2 = Point(king.x + kdx[1], king.y + kdy[1]);
    p1 = Point(king.x, king.y + 2);
    p2 = Point(king.x + 1, king.y + 2);
  }
  if (dir == 3) {
    pp1 = Point(king.x + kdx[0], king.y + kdy[0]);
    pp2 = Point(king.x + kdx[2], king.y + kdy[2]);
    p1 = Point(king.x + 2, king.y);
    p2 = Point(king.x + 2, king.y + 1);
  }
  if (!(exist[pp1] && exist[pp2]))
    return false;

  return true;
}

void dijkstra(Point st, Point op1, Point op2) {
  priority_queue<State> Q;
  Q.push(State(st, op1, op2, 0));
  // mincost[toIndex(op1)][toIndex(op2)][toIndex(st)] = 0;
  // mincost[toIndex(op2)][toIndex(op1)][toIndex(st)] = 0;
  mincost[iii(ii(toIndex(op1), toIndex(op2)), toIndex(st))] = true;
  mincost[iii(ii(toIndex(op2), toIndex(op1)), toIndex(st))] = true;

  while (!Q.empty()) {
    State state = Q.top();
    Q.pop();
    // cout << "the cost = " << state.cost << endl;
    // trace(state.op[0],state.op[1],state.king);
    if (toIndex(state.king) == 0) {
      cout << state.cost << endl;
      return;
    }

    Point king = state.king;
    rep(i, 2) // move the open square
    {
      Point p = state.op[i];
      rep(j, 4) {
        int nx = p.x + dx[j];
        int ny = p.y + dy[j];
        if (!(0 <= nx && nx < w && 0 <= ny && ny < h))
          continue;
        if (G[ny][nx] == '*')
          continue;

        bool check_king = true;
        rep(k, 4) { // the place (ny,ny) is on the king
          int kx = king.x + kdx[k];
          int ky = king.y + kdy[k];
          assert(0 <= kx && kx < w && 0 <= ky && ky < h);
          if (kx == nx && ky == ny) {
            check_king = false;
            break;
          }
        }
        if (!check_king)
          continue;
        if (nx == state.op[(i + 1) % 2].x && ny == state.op[(i + 1) % 2].y)
          continue; // the new place is on the other open squeare

        Point pp[2];
        pp[0] = (i == 0 ? Point(nx, ny) : state.op[0]);
        pp[1] = (i == 0 ? state.op[1] : Point(nx, ny));

        int index1 = toIndex(pp[0]);
        int index2 = toIndex(pp[1]);
        int index3 = toIndex(state.king);
        if (!mincost[iii(ii(index1, index2), index3)]) {
          mincost[iii(ii(index1, index2), index3)] = true;
          mincost[iii(ii(index2, index1), index3)] = true;
          Q.push(State(state.king, pp[0], pp[1], state.cost + 1));
        }
      }
    }

    rep(i, 4) // move the king
    {
      int nx = state.king.x + dx[i];
      int ny = state.king.y + dy[i];
      Point sop1 = state.op[0];
      Point sop2 = state.op[1];
      if (!slide_check(i, sop1, sop2, Point(nx, ny)))
        continue;

      int index1 = toIndex(sop1);
      int index2 = toIndex(sop2);
      int index3 = toIndex(Point(nx, ny));
      // if(mincost[index1][index2][index3] > state.cost + 1)
      if (!mincost[iii(ii(index1, index2), index3)]) {
        mincost[iii(ii(index1, index2), index3)] = true;
        mincost[iii(ii(index2, index1), index3)] = true;
        // mincost[index1][index2][index3] = state.cost + 1;
        // mincost[index2][index1][index3] = state.cost + 1;
        Q.push(State(Point(nx, ny), sop1, sop2, state.cost + 1));
      }
    }
  }
  cout << -1 << endl;
}

int main() {
  clock_t stc, edc;
  stc = clock();
  while (cin >> h >> w, h | w) {
    mincost.clear();
    Point st;
    vector<Point> op;
    rep(i, h) {
      cin >> G[i];
      rep(j, w) {
        if ((st.x == -1 && st.y == -1) && G[i][j] == 'X') {
          st.x = j, st.y = i;
        }
        if (G[i][j] == '.')
          op.push_back(Point(j, i));
      }
    }
    assert(op.size() == 2);
    dijkstra(st, op[0], op[1]);
  }
  edc = clock();
  // cout << setiosflags(ios::fixed) << setprecision(10) <<
  // (double)(edc-stc)/CLOCKS_PER_SEC << endl;
  return 0;
}