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

#include <algorithm>
#include <assert.h>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c)                                                           \\
  for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

const int HALF = 21;
const ll BASE = 1e+9 + 7;
int n;
int N;
int posX[15];
int posY[15];
int dist[15][15];
const int dx[4] = {-1, 0, 0, 1};
const int dy[4] = {-1, -1, 1, 1};

inline int Encode(int x, int y) {
  assert(x <= y);
  return y * (y + 1) / 2 + x;
}
inline void Decode(int code, int &x, int &y) {
  assert(0 <= code && code < 15);
  x = posX[code];
  y = posY[code];
}

struct State {
  char cost;
  char a;
  char cards[15];
  int Get(int x, int y) { return cards[Encode(x, y)]; }
  void Set(int x, int y, int v) { cards[Encode(x, y)] = v; }
  void Swap(int x1, int y1, int x2, int y2) {
    swap(cards[Encode(x1, y1)], cards[Encode(x2, y2)]);
  }
  void Holl(int &rx, int &ry) {
    REP(i, N) {
      if (cards[i] == 1) {
        rx = posX[i];
        ry = posY[i];
        return;
      }
    }
    assert(false);
  }
  int HollX() {
    int x, y;
    Holl(x, y);
    return x;
  }
  int HollY() {
    int x, y;
    Holl(x, y);
    return y;
  }
  void CalcA() {
    int rev[16];
    REP(i, N) { rev[(int)cards[i] - 1] = i; }

    a = 0;
    FOR(i, 1, N) { a += dist[rev[i]][i]; }
    FOR(i, 3, N) {
      if (cards[i] == i + 1) {
        continue;
      }
      int fx = posX[i];
      int fy = posY[i];
      REP(dir, 4) {
        int nx = fx + dx[dir];
        int ny = fy + dy[dir];
        if (nx < 0 || nx > ny || ny < 0 || ny >= n) {
          continue;
        }
        if (cards[Encode(nx, ny)] != Encode(nx, ny) + 1) {
          goto next;
        }
      }
      a += 6;
    next:;
    }
    if (a != 0 && n == 5) {
      if (cards[0] == 1 && cards[1] == 2 && cards[2] == 3) {
        a += 6;
      }
      if ((cards[0] == 1 || cards[1] == 1 || cards[2] == 1) &&
          (cards[3] == 4 && cards[4] == 5 && cards[5] == 6) &&
          (cards[6] != 7 || cards[7] != 8 || cards[8] != 9 || cards[9] != 10 ||
           cards[11] != 12 || cards[12] != 13 || cards[13] != 14)) {
        a += 6;
      }
      if ((cards[0] == 1 || cards[1] == 1 || cards[2] == 1 || cards[3] == 1 ||
           cards[4] == 1 || cards[5] == 1) &&
          (cards[6] == 7 || cards[7] == 8 || cards[8] == 9) &&
          (cards[9] != 10 || cards[11] != 12 || cards[12] != 13 ||
           cards[13] != 14)) {
        a += 6;
      }
    }
  }
  ull Hash() {
    ll ret = 0;
    REP(i, N) { ret = ret * BASE + cards[i]; }
    return ret;
  }
  bool operator<(const State &rhs) const { return cost + a > rhs.cost + rhs.a; }
};

map<ull, char> half[6];
void CalcHalfSide(int m) {
  n = m;
  N = n * (n + 1) / 2;
  State ini;
  ini.cost = 0;
  REP(i, N) { ini.cards[i] = i + 1; }
  queue<State> que;
  que.push(ini);
  half[m][ini.Hash()] = 0;

  while (!que.empty()) {
    State s = que.front();
    que.pop();
    if (s.cost == HALF) {
      continue;
    }

    int hx, hy;
    s.Holl(hx, hy);
    REP(dir, 4) {
      int nx = hx + dx[dir];
      int ny = hy + dy[dir];
      if (nx < 0 || nx > ny || ny < 0 || ny >= n) {
        continue;
      }
      State ns = s;
      ns.Swap(hx, hy, nx, ny);
      ns.cost++;
      ull h = ns.Hash();
      if (half[m].count(h) && half[m][h] <= ns.cost) {
        continue;
      }
      half[m][h] = ns.cost;
      que.push(ns);
    }
  }
}

int main() {
  REP(y, 5) {
    REP(x, y + 1) {
      posX[Encode(x, y)] = x;
      posY[Encode(x, y)] = y;
    }
  }
  FOREQ(i, 1, 5) { CalcHalfSide(i); }
  int test_case = 0;
  while (scanf("%d", &n), n) {
    test_case++;
    N = n * (n + 1) / 2;

    // calc dist
    MEMSET(dist, 0x0f);
    REP(i, N) { dist[i][i] = 0; }
    REP(i, N) {
      int fx = posX[i];
      int fy = posY[i];
      REP(dir, 4) {
        int nx = fx + dx[dir];
        int ny = fy + dy[dir];
        if (nx < 0 || nx > ny || ny < 0 || ny >= n) {
          continue;
        }
        dist[i][Encode(nx, ny)] = 1;
      }
    }
    REP(k, N) REP(i, N) REP(j, N) {
      dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
    }

    // Get Input
    State ini;
    ini.cost = 0;
    REP(y, n) {
      REP(x, y + 1) {
        int v;
        scanf("%d", &v);
        ini.Set(x, y, v);
      }
    }
    if (ini.Get(0, n - 1) != Encode(0, n - 1) + 1) {
      ini.Swap(0, n - 1, 0, n - 2);
      ini.cost++;
    }
    if (ini.Get(n - 1, n - 1) != Encode(n - 1, n - 1) + 1) {
      ini.Swap(n - 1, n - 1, n - 2, n - 2);
      ini.cost++;
    }
    ini.CalcA();
    int x, y;
    ini.Holl(x, y);

    // A*
    map<ull, int> dists;
    priority_queue<State> que;
    que.push(ini);
    dists[ini.Hash()] = 0;
    int ans = 45;
    while (!que.empty()) {
      State s = que.top();
      que.pop();
      if (s.a == 0) {
        ans = s.cost;
        break;
      }
      if (half[n].count(s.Hash())) {
        ans = min(ans, s.cost + half[n][s.Hash()]);
        // cout << "OK:" << " " << ans << endl;
        continue;
      }
      int hx, hy;
      s.Holl(hx, hy);
      REP(dir, 4) {
        int nx = hx + dx[dir];
        int ny = hy + dy[dir];
        if (nx < 0 || nx > ny || ny < 0 || ny >= n) {
          continue;
        }
        State ns = s;
        ns.Swap(hx, hy, nx, ny);
        ns.cost++;
        ns.CalcA();
        if (ns.cost > ans - HALF) {
          continue;
        }
        if (ns.cost + ns.a > ans) {
          continue;
        }
        ull h = ns.Hash();
        if (dists.count(h) && dists[h] <= ns.cost) {
          continue;
        }
        dists[h] = ns.cost;
        que.push(ns);
      }
    }
    printf("Case %d: %d\\n", test_case, ans);
  }
}

Error: MLE

Fixed submission:

#include <algorithm>
#include <assert.h>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c)                                                           \\
  for (__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

const int HALF = 23;
const ll BASE = 1e+9 + 7;
int n;
int N;
int posX[15];
int posY[15];
int dist[15][15];
const int dx[4] = {-1, 0, 0, 1};
const int dy[4] = {-1, -1, 1, 1};

inline int Encode(int x, int y) {
  assert(x <= y);
  return y * (y + 1) / 2 + x;
}
inline void Decode(int code, int &x, int &y) {
  assert(0 <= code && code < 15);
  x = posX[code];
  y = posY[code];
}

struct State {
  char cost;
  char a;
  char cards[15];
  int Get(int x, int y) { return cards[Encode(x, y)]; }
  void Set(int x, int y, int v) { cards[Encode(x, y)] = v; }
  void Swap(int x1, int y1, int x2, int y2) {
    swap(cards[Encode(x1, y1)], cards[Encode(x2, y2)]);
  }
  void Holl(int &rx, int &ry) {
    REP(i, N) {
      if (cards[i] == 1) {
        rx = posX[i];
        ry = posY[i];
        return;
      }
    }
    assert(false);
  }
  int HollX() {
    int x, y;
    Holl(x, y);
    return x;
  }
  int HollY() {
    int x, y;
    Holl(x, y);
    return y;
  }
  void CalcA() {
    int rev[16];
    REP(i, N) { rev[(int)cards[i] - 1] = i; }

    a = 0;
    FOR(i, 1, N) { a += dist[rev[i]][i]; }
    FOR(i, 3, N) {
      if (cards[i] == i + 1) {
        continue;
      }
      int fx = posX[i];
      int fy = posY[i];
      REP(dir, 4) {
        int nx = fx + dx[dir];
        int ny = fy + dy[dir];
        if (nx < 0 || nx > ny || ny < 0 || ny >= n) {
          continue;
        }
        if (cards[Encode(nx, ny)] != Encode(nx, ny) + 1) {
          goto next;
        }
      }
      a += 6;
    next:;
    }
    if (a != 0 && n == 5) {
      if (cards[0] == 1 && cards[1] == 2 && cards[2] == 3) {
        a += 6;
      }
      if ((cards[0] == 1 || cards[1] == 1 || cards[2] == 1) &&
          (cards[3] == 4 && cards[4] == 5 && cards[5] == 6) &&
          (cards[6] != 7 || cards[7] != 8 || cards[8] != 9 || cards[9] != 10 ||
           cards[11] != 12 || cards[12] != 13 || cards[13] != 14)) {
        a += 6;
      }
      if ((cards[0] == 1 || cards[1] == 1 || cards[2] == 1 || cards[3] == 1 ||
           cards[4] == 1 || cards[5] == 1) &&
          (cards[6] == 7 || cards[7] == 8 || cards[8] == 9) &&
          (cards[9] != 10 || cards[11] != 12 || cards[12] != 13 ||
           cards[13] != 14)) {
        a += 6;
      }
    }
  }
  ull Hash() {
    ll ret = 0;
    REP(i, N) { ret = ret * BASE + cards[i]; }
    return ret;
  }
  bool operator<(const State &rhs) const { return cost + a > rhs.cost + rhs.a; }
};

map<ull, char> half[6];
void CalcHalfSide(int m) {
  n = m;
  N = n * (n + 1) / 2;
  State ini;
  ini.cost = 0;
  REP(i, N) { ini.cards[i] = i + 1; }
  queue<State> que;
  que.push(ini);
  half[m][ini.Hash()] = 0;

  while (!que.empty()) {
    State s = que.front();
    que.pop();
    if (s.cost == HALF) {
      continue;
    }

    int hx, hy;
    s.Holl(hx, hy);
    REP(dir, 4) {
      int nx = hx + dx[dir];
      int ny = hy + dy[dir];
      if (nx < 0 || nx > ny || ny < 0 || ny >= n) {
        continue;
      }
      State ns = s;
      ns.Swap(hx, hy, nx, ny);
      ns.cost++;
      ull h = ns.Hash();
      if (half[m].count(h) && half[m][h] <= ns.cost) {
        continue;
      }
      half[m][h] = ns.cost;
      que.push(ns);
    }
  }
}

int main() {
  REP(y, 5) {
    REP(x, y + 1) {
      posX[Encode(x, y)] = x;
      posY[Encode(x, y)] = y;
    }
  }
  FOREQ(i, 1, 5) { CalcHalfSide(i); }
  int test_case = 0;
  while (scanf("%d", &n), n) {
    test_case++;
    N = n * (n + 1) / 2;

    // calc dist
    MEMSET(dist, 0x0f);
    REP(i, N) { dist[i][i] = 0; }
    REP(i, N) {
      int fx = posX[i];
      int fy = posY[i];
      REP(dir, 4) {
        int nx = fx + dx[dir];
        int ny = fy + dy[dir];
        if (nx < 0 || nx > ny || ny < 0 || ny >= n) {
          continue;
        }
        dist[i][Encode(nx, ny)] = 1;
      }
    }
    REP(k, N) REP(i, N) REP(j, N) {
      dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
    }

    // Get Input
    State ini;
    ini.cost = 0;
    REP(y, n) {
      REP(x, y + 1) {
        int v;
        scanf("%d", &v);
        ini.Set(x, y, v);
      }
    }
    if (ini.Get(0, n - 1) != Encode(0, n - 1) + 1) {
      ini.Swap(0, n - 1, 0, n - 2);
      ini.cost++;
    }
    if (ini.Get(n - 1, n - 1) != Encode(n - 1, n - 1) + 1) {
      ini.Swap(n - 1, n - 1, n - 2, n - 2);
      ini.cost++;
    }
    ini.CalcA();
    int x, y;
    ini.Holl(x, y);

    // A*
    map<ull, int> dists;
    priority_queue<State> que;
    que.push(ini);
    dists[ini.Hash()] = 0;
    int ans = 45;
    while (!que.empty()) {
      State s = que.top();
      que.pop();
      if (s.a == 0) {
        ans = s.cost;
        break;
      }
      if (half[n].count(s.Hash())) {
        ans = min(ans, s.cost + half[n][s.Hash()]);
        // cout << "OK:" << " " << ans << endl;
        continue;
      }
      int hx, hy;
      s.Holl(hx, hy);
      REP(dir, 4) {
        int nx = hx + dx[dir];
        int ny = hy + dy[dir];
        if (nx < 0 || nx > ny || ny < 0 || ny >= n) {
          continue;
        }
        State ns = s;
        ns.Swap(hx, hy, nx, ny);
        ns.cost++;
        ns.CalcA();
        if (ns.cost > ans - HALF) {
          continue;
        }
        if (ns.cost + ns.a > ans) {
          continue;
        }
        ull h = ns.Hash();
        if (dists.count(h) && dists[h] <= ns.cost) {
          continue;
        }
        dists[h] = ns.cost;
        que.push(ns);
      }
    }
    printf("Case %d: %d\\n", test_case, ans);
  }
}