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

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

template <class T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T> bool chmin(T &a, const T &b) {
  if (b < a) {
    a = b;
    return 1;
  }
  return 0;
}

#define FOR(i, a, b) for (ll i = (a); i < (b); ++i)
#define ALL(v) (v).begin(), (v).end()
#define p(s) cout << (s) << endl
#define p2(s, t) cout << (s) << " " << (t) << endl
#define br() p("")
#define pn(s) cout << (#s) << " " << (s) << endl

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

const int W = 4;

// ofstream of;

struct Point {
  ll x;
  ll y;
  Point(ll x, ll y) : x(x), y(y) {}
  Point() {}

  bool operator==(const Point &b) const {
    if (x == b.x && y == b.y) {
      return true;
    } else {
      return false;
    }
  }
};

struct Puzzle {
  ll A[W][W];
  vector<ll> path;

  Point get_space() {
    Point p;
    FOR(y, 0, W) {
      FOR(x, 0, W) {
        if (A[y][x] == 0) {
          p.x = x;
          p.y = y;
          return p;
        }
      }
    }
    return p;
  }

  bool operator<(const Puzzle &b) const {
    FOR(y, 0, W) {
      FOR(x, 0, W) {
        if (A[y][x] != b.A[y][x]) {
          return A[y][x] < b.A[y][x];
        }
      }
    }
    return false;
  }

  bool is_solved() {
    if (manhattan_distance() == 0) {
      return true;
    } else {
      return false;
    }
  }

  // 各マスの目的位置までのマンハッタン距離の和
  ll manhattan_distance() {
    ll sum = 0;
    FOR(y, 0, W) {
      FOR(x, 0, W) {
        ll v = A[y][x];
        ll tx, ty; // 最終的にいるべき場所
        // 0はMDに含めない
        if (v != 0) {
          v--;
          tx = v % W;
          ty = v / W;
          ll dist = abs(x - tx) + abs(y - ty);
          sum += dist;
        }
      }
    }
    return sum;
  }

  void print() {
    FOR(y, 0, W) {
      FOR(x, 0, W) {
        //  << setw(2) << A[y][x] << ' ';
      }
      // of << endl;
    }
  }
};

// depth : 現在深度
bool dfs(ll depth, ll limit, Puzzle pz, Point prev) {
  // of << endl << "depth " << depth << endl;
  // pz.print();

  // pn(depth);
  ll MD = pz.manhattan_distance();
  if (MD == 0) {
    return true;
  }

  // pruning
  if (depth + MD > limit)
    return false;

  auto sp = pz.get_space();

  // 解けてないなら4方向へ移動
  FOR(i, 0, 4) {
    ll sx = sp.x;
    ll sy = sp.y;

    // target position
    ll tx = sx + dx[i];
    ll ty = sy + dy[i];

    auto cp = pz;

    // in range
    if (0 <= tx && tx < W && 0 <= ty && ty < W) {
      swap(cp.A[sy][sx], cp.A[ty][tx]);

      bool is_new_destination = true;
      if (cp.get_space() == prev) {
        is_new_destination = false;
      }

      if (is_new_destination && dfs(depth + 1, limit, cp, sp)) {
        return true;
      }
    }
  }
  return false;
}

ll iterative_deepening(Puzzle pz) {
  ll MD = pz.manhattan_distance();
  FOR(limit, MD, 100) {
    // pn(limit);
    Point prev;
    prev.x = -1;
    prev.y = -1;

    bool f = dfs(0, limit, pz, prev);
    if (f) {
      return limit;
    }
  }
  return -1;
}

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  // of.open("log.txt");

  // 初期状態
  auto p = Puzzle();
  FOR(y, 0, W) {
    FOR(x, 0, W) { cin >> p.A[y][x]; }
  }

  // p.print();

  ll ans = iterative_deepening(p);
  p(ans);

  return 0;
}


Error: MLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

template <class T> bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T> bool chmin(T &a, const T &b) {
  if (b < a) {
    a = b;
    return 1;
  }
  return 0;
}

#define FOR(i, a, b) for (ll i = (a); i < (b); ++i)
#define ALL(v) (v).begin(), (v).end()
#define p(s) cout << (s) << endl
#define p2(s, t) cout << (s) << " " << (t) << endl
#define br() p("")
#define pn(s) cout << (#s) << " " << (s) << endl

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

const int W = 4;

struct Point {
  ll x;
  ll y;
  Point(ll x, ll y) : x(x), y(y) {}
  Point() {}
};

struct Puzzle {
  ll A[W][W];
  vector<ll> path;

  Point get_space() {
    Point p;
    FOR(y, 0, W) {
      FOR(x, 0, W) {
        if (A[y][x] == 0) {
          p.x = x;
          p.y = y;
          return p;
        }
      }
    }
    return p;
  }

  bool operator<(const Puzzle &b) const {
    FOR(y, 0, W) {
      FOR(x, 0, W) {
        if (A[y][x] != b.A[y][x]) {
          return A[y][x] < b.A[y][x];
        }
      }
    }
    return false;
  }

  bool is_solved() {
    FOR(y, 0, W) {
      FOR(x, 0, W) {
        ll target = W * y + x + 1;
        if (y == W - 1 && x == W - 1)
          target = 0;
        if (A[y][x] != target)
          return false;
      }
    }
    return true;
  }

  void print() {
    FOR(y, 0, W) {
      FOR(x, 0, W) { cout << A[y][x] << ' '; }
      cout << endl;
    }
  }
};

int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);

  // 初期状態
  auto p = Puzzle();
  FOR(y, 0, W) {
    FOR(x, 0, W) { cin >> p.A[y][x]; }
  }

  map<Puzzle, bool> mp;
  mp[p] = true;

  queue<Puzzle> que;
  que.push(p);

  while (!que.empty()) {
    auto pu = que.front();
    que.pop();

    if (pu.is_solved()) {
      p(pu.path.size());
      return 0;
    }

    FOR(i, 0, 4) {
      auto sp = pu.get_space();
      ll x = sp.x;
      ll y = sp.y;

      // target position
      ll tx = x + dx[i];
      ll ty = y + dy[i];

      auto cp = pu;

      // in range
      if (0 <= tx && tx < W && 0 <= ty && ty < W) {
        swap(cp.A[y][x], cp.A[ty][tx]);

        // まだその状態になったことがないなら入れる
        if (mp[cp] != true) {
          mp[cp] = true;
          cp.path.push_back(i);
          que.push(cp);
        }
      }
    }
  }

  return 0;
}