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

#include <array>
#include <cmath>
#include <iostream>
#include <queue>
#include <set>
#include <vector>

using namespace std;

const int N = 4;
const int N2 = N * N;

int MDT[N2][N2];

struct Puzzle {
  array<char, N2> board;
  int empty;
  int cost;
  int rank;

  bool operator<(const Puzzle &other) const {
    return cost + rank > other.cost + other.rank;
  }
};

int distance(const Puzzle &p) {
  int d = 0;
  for (int i = 0; i < N2; ++i) {
    if (p.board[i] == N2)
      continue;
    d += MDT[i][p.board[i] - 1];
  }
  return d;
}

const vector<array<int, 2>> dir = {
    {-1, 0}, // left
    {0, -1}, // up
    {1, 0},  // right
    {0, 1},  // down
};

int astar(Puzzle start) {
  auto puzzle_less = [](const Puzzle &a, const Puzzle &b) {
    for (int i = 0; i < N2; ++i) {
      if (a.board[i] != b.board[i])
        return a.board[i] < b.board[i];
    }
    return false;
  };

  Puzzle ans;
  set<Puzzle, decltype(puzzle_less)> visited(puzzle_less);
  priority_queue<Puzzle> Q;
  Q.push(start);
  while (!Q.empty()) {
    auto u = Q.top();
    Q.pop();
    if (u.rank == 0) {
      return u.cost;
    }
    visited.insert(u);

    auto sx = u.empty % N;
    auto sy = u.empty / N;
    for (auto &d : dir) {
      auto tx = sx + d[0];
      auto ty = sy + d[1];
      if (tx < 0 || ty < 0 || tx >= N || ty >= N) {
        continue;
      }
      auto v = u;

      auto k = tx + ty * N;
      swap(v.board[v.empty], v.board[k]);
      v.empty = k;
      v.rank = distance(v);
      if (visited.find(v) == visited.end()) {
        ++v.cost;
        Q.push(v);
      }
    }
  }
  return -1;
}

int main() {
  for (int i = 0; i < N2; ++i) {
    for (int j = 0; j < N2; ++j) {
      // iからjへのマンハッタン距離
      MDT[i][j] = abs(i / N - j / N) + abs(i % N - j % N);
    }
  }

  Puzzle start;
  for (int i = 0; i < N2; ++i) {
    int x;
    cin >> x;
    start.board[i] = x;
    if (x == 0) {
      start.board[i] = N2;
      start.empty = i;
    }
  }
  start.cost = 0;
  start.rank = distance(start);
  cout << astar(start) << endl;

  return 0;
}


Error: MLE

Fixed submission:

#include <array>
#include <iostream>
#include <queue>
#include <set>
#include <vector>

using namespace std;

const int N = 4;

struct Puzzle {
  array<array<char, N>, N> board;
  array<int, 2> empty;
  array<int, 2> last;
  int cost;
  int rank;

  bool operator<(const Puzzle &other) const {
    return cost + rank > other.cost + other.rank;
  }
};

int distance(const Puzzle &p) {
  const auto M = N - 1;
  int d = 0;
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
      auto x = p.board[i][j];
      if (x == 0)
        x = 16;
      auto m = (x - 1) % N;
      auto n = (x - 1) / N;

      auto dx = i - m;
      auto dy = j - n;
      if (dx < 0)
        dx = -dx;
      if (dy < 0)
        dy = -dy;
      d += dx + dy;
    }
  }
  return d;
}

const vector<array<int, 2>> dir = {
    {-1, 0}, // left
    {0, -1}, // up
    {1, 0},  // right
    {0, 1},  // down
};

bool solved(const Puzzle &p) {
  const auto M = N - 1;
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
      int x = i == M && j == M ? 0 : i * N + j + 1;
      if (p.board[i][j] != x) {
        return false;
      }
    }
  }
  return true;
}

int main() {
  Puzzle start;
  start.cost = 0;
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
      int x;
      cin >> x;
      if (x == 0) {
        start.empty = {i, j};
      }
      start.board[i][j] = x;
    }
  }
  start.rank = distance(start);
  start.last = {0, 0};

  Puzzle ans;
  priority_queue<Puzzle> Q;
  Q.push(start);
  while (!Q.empty()) {
    auto u = Q.top();
    Q.pop();
    if (solved(u)) {
      ans = std::move(u);
      break;
    }
    for (auto &d : dir) {
      auto tx = u.empty[0] + d[0];
      auto ty = u.empty[1] + d[1];
      if (tx < 0 || ty < 0 || tx >= N || ty >= N) {
        continue;
      }
      if (tx == u.last[0] && ty == u.last[1]) {
        continue;
      }
      auto v = u;
      swap(v.board[v.empty[0]][v.empty[1]], v.board[tx][ty]);
      v.last = v.empty;
      v.empty = {tx, ty};
      ++v.cost;
      v.rank = distance(v);
      Q.push(v);
    }
  }
  cout << ans.cost << endl;

  return 0;
}