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

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>
#include <set>
#include <utility>
#include <vector>

using namespace std;

template <class T> using gp_queue = priority_queue<T, deque<T>, less<T>>;

const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, -1, 0, 1};

struct Puzzle {
  vector<size_t> board;
  size_t cost, mdistance, gap;
  Puzzle() : board(16), cost(0), mdistance(0) {}
  Puzzle(vector<size_t> &b) : board(b), cost(0), mdistance(0) {}
  bool operator<(const Puzzle &rhs) const {
    for (size_t i = 0; i < 16; ++i)
      if (board[i] != rhs.board[i])
        return board[i] < rhs.board[i];

    return false;
  }
};

size_t calc_mdistance(Puzzle p, const vector<vector<size_t>> &dtable) {
  size_t mdistance = 0;
  for (size_t i = 0; i < 16; ++i)
    if (p.board[i] < 16)
      mdistance += dtable[i][p.board[i] - 1];

  return mdistance;
}

size_t encode(vector<size_t> d) {
  size_t cur = 0, enc = 0;
  for (size_t i = 0; i < 15; ++i)
    if (d[i] == 16) {
      d[i] = 0;
      break;
    }

  for (size_t i = 0; i < 15; ++i) {
    cur = d[i];
    for (size_t j = i + 1; j < 16; ++j)
      if (cur < d[j])
        --d[j];

    (enc += d[i]) *= 15 - i;
  }

  return enc;
}

struct State {
  Puzzle puzzle;
  size_t hcost;
  State() {}
  State(Puzzle &p) : puzzle(p) {}
  bool operator<(const State &rhs) const { return hcost > rhs.hcost; }
};

size_t astar(Puzzle p, const vector<vector<size_t>> &dtable) {
  p.mdistance = calc_mdistance(p, dtable);
  p.cost = 0;
  State init(p);
  init.hcost = p.mdistance;

  set<size_t> visited;
  gp_queue<State> q;
  q.push(init);
  while (!q.empty()) {
    State s = q.top();
    q.pop();
    Puzzle u = s.puzzle;

    if (!u.mdistance)
      return u.cost;

    visited.insert(encode(u.board));
    size_t sx = u.gap / 4, sy = u.gap % 4;
    for (size_t r = 0; r < 4; ++r) {
      size_t tx = sx + dx[r], ty = sy + dy[r];
      if (!(0 <= tx && tx < 4 && 0 <= ty && ty < 4))
        continue;

      Puzzle v = u;
      v.gap = tx * 4 + ty;
      v.mdistance -= dtable[tx * 4 + ty][v.board[tx * 4 + ty] - 1];
      v.mdistance += dtable[sx * 4 + sy][v.board[tx * 4 + ty] - 1];
      swap(v.board[sx * 4 + sy], v.board[tx * 4 + ty]);

      if (!visited.count(encode(v.board))) {
        ++v.cost;
        State nstate(v);
        nstate.hcost = v.cost + v.mdistance;
        q.push(nstate);
      }
    }
  }
  return -1;
}

int main() {
  vector<vector<size_t>> dtable(16, vector<size_t>(16));
  for (size_t i = 0; i < 16; ++i)
    for (size_t j = 0; j < 16; ++j)
      dtable[i][j] = abs(int(i / 4 - j / 4)) + abs(int(i % 4 - j % 4));

  Puzzle in;
  for (size_t i = 0; i < 16; ++i) {
    scanf("%zu", &in.board[i]);
    if (!in.board[i]) {
      in.board[i] = 16;
      in.gap = i;
    }
  }

  printf("%zd\\n", astar(in, dtable));
  return 0;
}

Error: MLE

Fixed submission:

#include <cmath>
#include <cstdio>
#include <queue>
#include <set>
#include <vector>

using namespace std;

template <class T> using gp_queue = priority_queue<T, deque<T>, less<T>>;

const int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, -1, 0, 1};

struct Puzzle {
  vector<size_t> board;
  size_t cost, mdistance, gap;
  Puzzle() : board(16), cost(0), mdistance(0) {}
  Puzzle(vector<size_t> &b) : board(b), cost(0), mdistance(0) {}
  bool operator<(const Puzzle &rhs) const {
    for (size_t i = 0; i < 16; ++i)
      if (board[i] != rhs.board[i])
        return board[i] < rhs.board[i];

    return false;
  }
};

size_t calc_mdistance(Puzzle p, const vector<vector<size_t>> &dtable) {
  size_t mdistance = 0;
  for (size_t i = 0; i < 16; ++i)
    if (p.board[i] < 16)
      mdistance += dtable[i][p.board[i] - 1];

  return mdistance;
}

struct State {
  Puzzle puzzle;
  size_t hcost;
  State() {}
  State(Puzzle &p) : puzzle(p) {}
  State(Puzzle &p, const vector<vector<size_t>> &dtable) : puzzle(p) {
    hcost = calc_mdistance(p, dtable);
  }
  bool operator<(const State &rhs) const { return hcost > rhs.hcost; }
};

size_t astar(Puzzle p, const vector<vector<size_t>> &dtable) {
  p.mdistance = calc_mdistance(p, dtable);
  p.cost = 0;
  State init(p, dtable);

  set<Puzzle> visited;
  gp_queue<State> q;
  q.push(init);
  while (!q.empty()) {
    State s = q.top();
    q.pop();
    Puzzle u = s.puzzle;

    if (!u.mdistance)
      return u.cost;

    visited.insert(u);
    size_t sx = u.gap / 4, sy = u.gap % 4;
    for (size_t r = 0; r < 4; ++r) {
      size_t tx = sx + dx[r], ty = sy + dy[r];
      if (!(0 <= tx && tx < 4 && 0 <= ty && ty < 4))
        continue;

      Puzzle v = u;
      v.gap = tx * 4 + ty;
      v.mdistance -= dtable[tx * 4 + ty][v.board[tx * 4 + ty] - 1];
      v.mdistance += dtable[sx * 4 + sy][v.board[tx * 4 + ty] - 1];
      swap(v.board[sx * 4 + sy], v.board[tx * 4 + ty]);

      if (!visited.count(v)) {
        ++v.cost;
        State nstate(v);
        nstate.hcost = v.cost + v.mdistance;
        q.push(nstate);
      }
    }
  }
  return -1;
}

int main() {
  vector<vector<size_t>> dtable(16, vector<size_t>(16));
  for (size_t i = 0; i < 16; ++i)
    for (size_t j = 0; j < 16; ++j)
      dtable[i][j] = abs(int(i / 4 - j / 4)) + abs(int(i % 4 - j % 4));

  Puzzle in;
  for (size_t i = 0; i < 16; ++i) {
    scanf("%zu", &in.board[i]);
    if (!in.board[i]) {
      in.board[i] = 16;
      in.gap = i;
    }
  }

  printf("%zd\\n", astar(in, dtable));
  return 0;
}