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

#include <cstdio>
#include <iostream>
#include <vector>

#define RC2P(r, c) (((r) << 2) + (c)) // r*4+c
#define P2R(p) ((p) >> 2)             // p/4
#define P2C(p) ((p)&3)                // p%4
#define HASHMAX 1000003

typedef unsigned long long int Pkey;

int dist(Pkey x, int t);
int abs(int x);

struct Pandt {
  Pkey p;
  int t;
  int w;

  Pandt() { return; }
  Pandt(Pkey p, int t) : p(p), t(t) {
    w = dist(p, t);
    return;
  }

  bool operator==(const Pandt &rhs) const { return (p == rhs.p && t == rhs.t); }
};

void insert(std::vector<Pandt> &A, Pandt v);
Pandt extract(std::vector<Pandt> &A);
int SolvePuzzle(std::vector<int> P);

std::vector<Pandt> Puzzles(HASHMAX);
std::vector<int> mds(HASHMAX);

int h1(Pkey key) { return (int)(key % HASHMAX); }
int h2(Pkey key) { return (int)((key % (HASHMAX - 1)) + 1); }
int HashFind(Pkey key);
int HashInsert(Pkey key, int val);

void InitHash() {
  Pandt Nullpandt(0, -1);
  for (int i = 0; i < HASHMAX; i++) {
    Puzzles[i] = Nullpandt;
  }
}

int HashFind(Pkey key) {

  int curhash = h1(key);
  int sechash = -1;
  for (int i = 0; i < HASHMAX; i++) {
    if (Puzzles[curhash].t == -1) {
      return -1;
    } else if (Puzzles[curhash].p == key) {
      return curhash;
    } else {
      if (sechash == -1)
        sechash = h2(key);
      curhash = (curhash + sechash) % HASHMAX;
    }
  }
  return -1;
}

int HashInsert(Pkey key, int val) {

  int curhash = h1(key);
  int sechash = -1;
  for (int i = 0; i < HASHMAX; i++) {
    if (Puzzles[curhash].t == -1) {
      Puzzles[curhash].t = val;
      Puzzles[curhash].p = key;
      return curhash;
    } else {
      if (sechash == -1)
        sechash = h2(key);
      curhash = (curhash + sechash) % HASHMAX;
    }
  }
  return -1;
}

int dist(Pkey x, int t) {
  if (x == 0 && t == 0)
    return 0;
  int tmp, result = 0;
  for (int i = 0; i < 16; i++) {
    tmp = (x & ((Pkey)15 << (i << 2))) >> (i << 2);
    if (tmp == 0)
      continue;
    result += abs(P2C(tmp - 1) - P2C(i)) + abs(P2R(tmp - 1) - P2R(i));
  }
  return -result - t;
}

int abs(int x) { return x < 0 ? -x : x; }

bool comp(Pandt rhs, Pandt lhs) {
  return rhs.w == lhs.w ? rhs.t < lhs.t : rhs.w < lhs.w;
}

void insert(std::vector<Pandt> &A, Pandt v) {
  int n = A.size();
  A.push_back(v);
  Pandt tmp;
  while (n != 0) {
    int i = (n - 1) >> 1;
    if (comp(A[i], A[n])) {
      tmp = A[n];
      A[n] = A[i];
      A[i] = tmp;
    }
    n = i;
  }
  return;
}

Pandt extract(std::vector<Pandt> &A) {
  int n = A.size() - 1;
  Pandt tmp, res = A[0];
  A[0] = A[n];
  A.pop_back();

  for (int i = 0, j; (i << 1) + 1 < n;) {
    j = (i << 1) + 1;
    if (j != n - 1 && comp(A[j], A[j + 1])) {
      j++;
    }
    if (comp(A[i], A[j])) {
      tmp = A[j];
      A[j] = A[i];
      A[i] = tmp;
    }
    i = j;
  }
  return res;
}

Pkey PtoI(std::vector<int> p) {
  unsigned long long int keyI = 0;
  for (int i = 0; i < 16; i++) {
    keyI += (unsigned long long int)(15 & p[i]) << (i << 2);
  }
  return keyI;
}

void AddToQueue(std::vector<Pandt> &Que, Pkey Qnext, Pandt ext) {
  int Qsearch = HashFind(Qnext);
  Pandt Qnextt(Qnext, ext.t + 1);
  if (Qsearch == -1) {
    HashInsert(Qnext, ext.t + 1);
    insert(Que, Qnextt);
  } else if (Puzzles[Qsearch].t > ext.t + 1) {
    insert(Que, Qnextt);
    Puzzles[Qsearch].t = ext.t + 1;
    Puzzles[Qsearch].w = Qnextt.w;
  }
  return;
}

int SolvePuzzle(std::vector<int> P) {
  std::vector<Pandt> Que;
  Pkey init = PtoI(P);
  Pandt initt(init, 0);
  insert(Que, initt);
  int answer = 45;
  while (true) {
    Pandt ext = extract(Que);
    int Cursor;
    if (ext.p == 0xFEDCBA987654321) {
      answer = ext.t;
      break;
    }

    if (-ext.w >= 45)
      break;

    for (int i = 0; i < 16; i++) {
      if ((ext.p & ((Pkey)15 << (i << 2))) == 0) {
        Cursor = i;
        break;
      }
    }
    Pkey Qnext;
    Pkey tmp;
    if (Cursor >= 4) {
      tmp = (ext.p & ((Pkey)15 << ((Cursor - 4) << 2)));
      Qnext = ext.p & ~tmp | (tmp << 16);
      AddToQueue(Que, Qnext, ext);
    }
    if (Cursor < 12) {
      tmp = (ext.p & ((Pkey)15 << ((Cursor + 4) << 2)));
      Qnext = ext.p & ~tmp | (tmp >> 16);
      AddToQueue(Que, Qnext, ext);
    }
    if (P2C(Cursor) != 0) {
      tmp = (ext.p & ((Pkey)15 << ((Cursor - 1) << 2)));
      Qnext = ext.p & ~tmp | (tmp << 4);
      AddToQueue(Que, Qnext, ext);
    }
    if (P2C(Cursor) != 3) {
      tmp = (ext.p & ((Pkey)15 << ((Cursor + 1) << 2)));
      Qnext = ext.p & ~tmp | (tmp >> 4);
      AddToQueue(Que, Qnext, ext);
    }
  }

  return answer;
}

int main() {

  InitHash();

  int k;
  std::vector<int> P;
  for (int i = 0; i < 16; i++) {
    scanf("%d", &k);
    P.push_back(k);
  }
  int n = SolvePuzzle(P);

  printf("%d\\n", n);

  return 0;
}


Error: TLE

Fixed submission:

#include <cstdio>
#include <iostream>
#include <vector>

#define RC2P(r, c) (((r) << 2) + (c)) // r*4+c
#define P2R(p) ((p) >> 2)             // p/4
#define P2C(p) ((p)&3)                // p%4
#define HASHMAX 1000003

typedef unsigned long long int Pkey;

int dist(Pkey x, int t);
int abs(int x);

struct Pandt {
  Pkey p;
  int t;
  int w;

  Pandt() { return; }
  Pandt(Pkey p, int t) : p(p), t(t) {
    w = dist(p, t);
    return;
  }

  bool operator==(const Pandt &rhs) const { return (p == rhs.p && t == rhs.t); }
};

void insert(std::vector<Pandt> &A, Pandt v);
Pandt extract(std::vector<Pandt> &A);
int SolvePuzzle(std::vector<int> P);

std::vector<Pandt> Puzzles(HASHMAX);
std::vector<int> mds(HASHMAX);

int h1(Pkey key) { return (int)(key % HASHMAX); }
int h2(Pkey key) { return (int)((key % (HASHMAX - 1)) + 1); }
int HashFind(Pkey key);
int HashInsert(Pkey key, int val);

void InitHash() {
  Pandt Nullpandt(0, -1);
  for (int i = 0; i < HASHMAX; i++) {
    Puzzles[i] = Nullpandt;
  }
}

int HashFind(Pkey key) {

  int curhash = h1(key);
  int sechash = -1;
  for (int i = 0; i < HASHMAX; i++) {
    if (Puzzles[curhash].t == -1) {
      return -1;
    } else if (Puzzles[curhash].p == key) {
      return curhash;
    } else {
      if (sechash == -1)
        sechash = h2(key);
      curhash = (curhash + sechash) % HASHMAX;
    }
  }
  return -1;
}

int HashInsert(Pkey key, int val) {

  int curhash = h1(key);
  int sechash = -1;
  for (int i = 0; i < HASHMAX; i++) {
    if (Puzzles[curhash].t == -1) {
      Puzzles[curhash].t = val;
      Puzzles[curhash].p = key;
      return curhash;
    } else {
      if (sechash == -1)
        sechash = h2(key);
      curhash = (curhash + sechash) % HASHMAX;
    }
  }
  return -1;
}

int dist(Pkey x, int t) {
  if (x == 0 && t == 0)
    return 0;
  int tmp, result = 0;
  for (int i = 0; i < 16; i++) {
    tmp = (x & ((Pkey)15 << (i << 2))) >> (i << 2);
    if (tmp == 0)
      continue;
    result += abs(P2C(tmp - 1) - P2C(i)) + abs(P2R(tmp - 1) - P2R(i));
  }
  return -result - t;
}

int abs(int x) { return x < 0 ? -x : x; }

void insert(std::vector<Pandt> &A, Pandt v) {
  int n = A.size();
  A.push_back(v);
  Pandt tmp;
  while (n != 0) {
    int i = (n - 1) >> 1;
    if (A[n].w > A[i].w) {
      tmp = A[n];
      A[n] = A[i];
      A[i] = tmp;
    }
    n = i;
  }
  return;
}

Pandt extract(std::vector<Pandt> &A) {
  int n = A.size() - 1;
  Pandt tmp, res = A[0];
  A[0] = A[n];
  A.pop_back();

  for (int i = 0, j; (i << 1) + 1 < n;) {
    j = (i << 1) + 1;
    if (j != n - 1 && A[j].w < A[j + 1].w) {
      j++;
    }
    if (A[i].w < A[j].w) {
      tmp = A[j];
      A[j] = A[i];
      A[i] = tmp;
    }
    i = j;
  }
  return res;
}

Pkey PtoI(std::vector<int> p) {
  unsigned long long int keyI = 0;
  for (int i = 0; i < 16; i++) {
    keyI += (unsigned long long int)(15 & p[i]) << (i << 2);
  }
  return keyI;
}

void AddToQueue(std::vector<Pandt> &Que, Pkey Qnext, Pandt ext) {
  int Qsearch = HashFind(Qnext);
  Pandt Qnextt(Qnext, ext.t + 1);
  if (Qsearch == -1) {
    HashInsert(Qnext, ext.t + 1);
    insert(Que, Qnextt);
  } else if (Puzzles[Qsearch].t > ext.t + 1) {
    insert(Que, Qnextt);
    Puzzles[Qsearch].t = ext.t + 1;
    Puzzles[Qsearch].w = Qnextt.w;
  }
  return;
}

int SolvePuzzle(std::vector<int> P) {
  std::vector<Pandt> Que;
  Pkey init = PtoI(P);
  Pandt initt(init, 0);
  insert(Que, initt);
  int answer = 44;
  while (true) {
    Pandt ext = extract(Que);
    int Cursor;
    if (ext.p == 0xFEDCBA987654321) {
      answer = ext.t;
      break;
    }

    if (-ext.w >= 44)
      break;

    for (int i = 0; i < 16; i++) {
      if ((ext.p & ((Pkey)15 << (i << 2))) == 0) {
        Cursor = i;
        break;
      }
    }
    Pkey Qnext;
    Pkey tmp;
    if (Cursor >= 4) {
      tmp = (ext.p & ((Pkey)15 << ((Cursor - 4) << 2)));
      Qnext = ext.p & ~tmp | (tmp << 16);
      AddToQueue(Que, Qnext, ext);
    }
    if (Cursor < 12) {
      tmp = (ext.p & ((Pkey)15 << ((Cursor + 4) << 2)));
      Qnext = ext.p & ~tmp | (tmp >> 16);
      AddToQueue(Que, Qnext, ext);
    }
    if (P2C(Cursor) != 0) {
      tmp = (ext.p & ((Pkey)15 << ((Cursor - 1) << 2)));
      Qnext = ext.p & ~tmp | (tmp << 4);
      AddToQueue(Que, Qnext, ext);
    }
    if (P2C(Cursor) != 3) {
      tmp = (ext.p & ((Pkey)15 << ((Cursor + 1) << 2)));
      Qnext = ext.p & ~tmp | (tmp >> 4);
      AddToQueue(Que, Qnext, ext);
    }
  }

  return answer;
}

int main() {

  InitHash();

  int k;
  std::vector<int> P;
  for (int i = 0; i < 16; i++) {
    scanf("%d", &k);
    P.push_back(k);
  }
  int n = SolvePuzzle(P);

  printf("%d\\n", n);

  return 0;
}