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

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <map>
#include <queue>
#include <vector>

using namespace std;

class Dice {

public:
  int top, bottom, north, south, west, east;

  static const int TOP = 0;
  static const int BOTTOM = 1;
  static const int NORTH = 2;
  static const int SOUTH = 3;
  static const int EAST = 4;
  static const int WEST = 5;

  Dice(int t = 0, int b = 1, int n = 2, int s = 3, int w = 5, int e = 4)
      : top(t), bottom(b), north(n), south(s), west(w), east(e) {}

  void setDice(int t, int b, int n, int s, int w, int e) {
    top = t;
    bottom = b, north = n;
    south = s, west = w;
    east = e;
  }

  void rotateNorth() { setDice(south, north, top, bottom, west, east); }
  void rotateSouth() { setDice(north, south, bottom, top, west, east); }
  void rotateEast() { setDice(west, east, north, south, bottom, top); }
  void rotateWest() { setDice(east, west, north, south, top, bottom); }
  void rotateCW() { setDice(top, bottom, west, east, south, north); }
  void rotateCCW() { setDice(top, bottom, east, west, north, south); }

  // in for loop this function is convenient
  // able to access variables like array
  // this function can only get specific variable
  int getAt(int pos) const {
    if (pos == TOP)
      return top;
    if (pos == BOTTOM)
      return bottom;
    if (pos == NORTH)
      return north;
    if (pos == SOUTH)
      return south;
    if (pos == WEST)
      return west;
    if (pos == EAST)
      return east;
  }

  // express state of this dice as a 6-base number.
  string getState() const {
    string res = "";
    for (int i = 0; i < 6; i++) {
      int pos = getAt(i);
      res += (pos + '0');
    }
    return res;
  }
};

struct State {
  int t, h, w, done;
  Dice dice;
  bool operator<(const State &st) const { return t > st.t; }
};

const int SIZE = 31;
const int INF = (1 << 28);
const int DONE = (1 << 6);
int T[SIZE][SIZE][DONE][6][6];

int W, H;
int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};
string order;

char field[SIZE][SIZE];

bool isInside(int h, int w) { return 0 <= h && h < H && 0 <= w && w < W; }

bool canMove(State &st) {
  int h = st.h;
  int w = st.w;
  if (field[h][w] == 'k')
    return false;
  if (field[h][w] == 'w')
    return true;

  int top = st.dice.getAt(Dice::TOP);
  string colstr = "rcgmby";

  if (colstr[top] != field[h][w])
    return false;

  int nexpos = __builtin_popcount(st.done);
  if (colstr[top] != order[nexpos])
    return false;

  bool res = ((st.done & (1 << nexpos)) == 0);
  st.done = st.done | (1 << nexpos);
  return res;
}

void input() {
  for (int i = 0; i < H; i++)
    for (int j = 0; j < W; j++)
      cin >> field[i][j];
  cin >> order;
}

void solve() {

  fill(T[0][0][0][0], T[0][0][0][0] + SIZE * SIZE * DONE * 6 * 6, INF);

  priority_queue<State> Q;

  for (int i = 0; i < H; i++)
    for (int j = 0; j < W; j++) {
      if (field[i][j] == '#') {
        State tmp = (State){0, i, j, 0, Dice()};
        Q.push(tmp);
        T[tmp.h][tmp.w][tmp.done][tmp.dice.getAt(Dice::TOP)]
         [tmp.dice.getAt(Dice::NORTH)] = 0;
        field[i][j] = 'w';
      }
    }

  const int comp = (1 << 6) - 1;
  int res = INF;

  while (!Q.empty()) {

    const State now = Q.top();
    Q.pop();

    if (now.done == comp)
      res = min(res, now.t);

    if (T[now.h][now.w][now.done][now.dice.getAt(Dice::TOP)]
         [now.dice.getAt(Dice::NORTH)] < now.t)
      continue;

    for (int i = 0; i < 4; i++) {
      // E S W N
      State nex = now;
      nex.h += dy[i];
      nex.w += dx[i];
      nex.t++;
      if (i == 0)
        nex.dice.rotateEast();
      if (i == 1)
        nex.dice.rotateSouth();
      if (i == 2)
        nex.dice.rotateWest();
      if (i == 3)
        nex.dice.rotateNorth();

      if (!isInside(nex.h, nex.w))
        continue;

      if (canMove(nex)) {
        if (T[nex.h][nex.w][nex.done][nex.dice.getAt(Dice::TOP)]
             [nex.dice.getAt(Dice::NORTH)] > nex.t) {
          T[nex.h][nex.w][nex.done][nex.dice.getAt(Dice::TOP)]
           [nex.dice.getAt(Dice::NORTH)] = nex.t;
          Q.push(nex);
        }
      }
    }
  }

  if (res == INF)
    cout << "unreachable" << endl;
  else
    cout << res << endl;
}

int main() {

  while (cin >> W >> H && W + H) {
    input();
    solve();
  }
  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <map>
#include <queue>
#include <vector>

using namespace std;

#define TOP 0
#define BOTTOM 1
#define NORTH 2
#define SOUTH 3
#define WEST 5
#define EAST 4

class Dice {

public:
  int top, bottom, north, south, west, east;

  Dice(int t = 0, int b = 1, int n = 2, int s = 3, int w = 5, int e = 4)
      : top(t), bottom(b), north(n), south(s), west(w), east(e) {}

  void setDice(int t, int b, int n, int s, int w, int e) {
    top = t;
    bottom = b, north = n;
    south = s, west = w;
    east = e;
  }

  void rotateNorth() { setDice(south, north, top, bottom, west, east); }
  void rotateSouth() { setDice(north, south, bottom, top, west, east); }
  void rotateEast() { setDice(west, east, north, south, bottom, top); }
  void rotateWest() { setDice(east, west, north, south, top, bottom); }
  void rotateCW() { setDice(top, bottom, west, east, south, north); }
  void rotateCCW() { setDice(top, bottom, east, west, north, south); }

  // in for loop this function is convenient
  // able to access variables like array
  // this function can only get specific variable
  int getAt(int pos) const {
    if (pos == TOP)
      return top;
    if (pos == BOTTOM)
      return bottom;
    if (pos == NORTH)
      return north;
    if (pos == SOUTH)
      return south;
    if (pos == WEST)
      return west;
    if (pos == EAST)
      return east;
  }

  // express state of this dice as a 6-base number.
  string getState() const {
    string res = "";
    for (int i = 0; i < 6; i++) {
      int pos = getAt(i);
      res += (pos + '0');
    }
    return res;
  }
};

struct Key {
  int h, w, done;
  Dice dice;
  bool operator<(const Key &k) const {
    if (h != k.h)
      return h < k.h;
    if (w != k.w)
      return w < k.w;
    if (done != k.done)
      return done < k.done;
    return dice.getState() < k.dice.getState();
  }
};

struct State {
  int t;
  Key key;
  bool operator<(const State &st) const { return t > st.t; }
};

const int SIZE = 31;
const int INF = (1 << 28);

map<Key, int> T;
int W, H;
int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};
string order;

char field[SIZE][SIZE];

bool isInside(int h, int w) { return 0 <= h && h < H && 0 <= w && w < W; }

bool canMove(State &st) {
  int h = st.key.h;
  int w = st.key.w;
  if (field[h][w] == 'k')
    return false;
  if (field[h][w] == 'w')
    return true;

  int top = st.key.dice.getAt(TOP);
  string colstr = "rcgmby";

  if (colstr[top] != field[h][w])
    return false;

  int nexpos = __builtin_popcount(st.key.done);
  if (colstr[top] != order[nexpos])
    return false;

  bool res = ((st.key.done & (1 << nexpos)) == 0);
  st.key.done = st.key.done | (1 << nexpos);
  return res;
}

void input() {
  for (int i = 0; i < H; i++)
    for (int j = 0; j < W; j++)
      cin >> field[i][j];
  cin >> order;
}

inline void solve() {
  T.clear();

  priority_queue<State> Q;

  for (int i = 0; i < H; i++)
    for (int j = 0; j < W; j++) {
      if (field[i][j] == '#') {
        Key tmp = (Key){i, j, 0, Dice()};
        Q.push((State){0, tmp});
        T[tmp] = 0;
        field[i][j] = 'w';
      }
    }

  const int comp = (1 << 6) - 1;
  int res = INF;

  while (!Q.empty()) {

    const State now = Q.top();
    Q.pop();

    if (now.key.done == comp) {
      res = min(res, now.t);
      break;
    }

    if (T[now.key] < now.t)
      continue;

    for (int i = 0; i < 4; i++) {
      // E S W N
      State nex = now;
      nex.key.h += dy[i];
      nex.key.w += dx[i];
      nex.t++;
      if (i == 0)
        nex.key.dice.rotateEast();
      if (i == 1)
        nex.key.dice.rotateSouth();
      if (i == 2)
        nex.key.dice.rotateWest();
      if (i == 3)
        nex.key.dice.rotateNorth();

      if (!isInside(nex.key.h, nex.key.w))
        continue;

      if (canMove(nex)) {
        if (T.count(nex.key) == 0 || T[nex.key] > nex.t) {
          T[nex.key] = nex.t;
          Q.push(nex);
        }
      }
    }
  }

  if (res == INF)
    cout << "unreachable" << endl;
  else
    cout << res << endl;
}

int main() {

  while (cin >> W >> H && W + H) {
    input();
    solve();
  }
  return 0;
}