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

#include <cassert>
#include <iostream>
#include <map>
#include <queue>

/* development:
 *     /\\  /\\  /\\  /\\  /\\
 *    / 0\\/ 1\\/ 2\\/ 3\\/ 4\\
 *    --------------------
 *   /\\ 5/\\ 6/\\ 7/\\ 8/\\ 9/
 *  /10\\/11\\/12\\/13\\/14\\/
 *  --------------------
 *  \\15/\\16/\\17/\\18/\\19/
 *   \\/  \\/  \\/  \\/  \\/
 *
 * roll / direction (top view)
 *   direction = 0:   direction = 1:
 *     1 /\\ 0             0
 *      /xx\\             ----
 *      ----             \\xx/
 *        2             1 \\/ 2
 */

using namespace std;
typedef pair<int, int> pii;

class Dice20 {

private:
  struct Face3 {
    int index[3];
    Face3(int f = -1, int s = -1, int t = -1) {
      index[0] = f;
      index[1] = s;
      index[2] = t;
    }
    void rotate() {
      int tmp = index[0];
      index[0] = index[1];
      index[1] = index[2];
      index[2] = tmp;
    }
  };
  static Face3 TABLE[3][20][20];
  static bool s_initialized;
  static void init_table(int t, int f1, int f2, int f3) {
    Face3 f(f1, f2, f3);
    for (int i = 0; i < 3; ++i) {
      for (int j = 0; j < 3; ++j) {
        TABLE[j][t][f.index[j]] = f;
      }
      f.rotate();
    }
  }

public:
  int dir, top, first;

  Dice20(int d, int t, int f) : dir(d), top(t), first(f) {
    if (!s_initialized) {
      s_initialized = true;
      for (int i = 0; i < 5; ++i) {
        // 0 - 4
        init_table(i, (i + 1) % 5, (i + 4) % 5, i + 5);
        // 5 - 9
        init_table(i + 5, i, i + 10, 10 + (i + 1) % 5);
        // 10 - 14
        init_table(i + 10, i + 5, 5 + (i + 4) % 5, i + 15);
        // 15 - 19
        init_table(i + 15, i + 10, 15 + (i + 4) % 5, 15 + (i + 1) % 5);
      }
    }
  }

  void roll(int f) {
    const Face3 &cur = TABLE[0][top][first];
    const Face3 &next = TABLE[(f + 1 + dir) % 3][cur.index[f]][top];
    top = cur.index[f];
    first = next.index[0];
    dir = 1 - dir;
  }
  int neighbor(int f) { return TABLE[0][top][first].index[f]; }
};

Dice20::Face3 Dice20::TABLE[3][20][20];
bool Dice20::s_initialized = false;

const int dx[2][3] = {{-1, 1, 0}, {0, 1, -1}};
const int dy[2][3] = {{0, 0, -1}, {1, 0, 0}};
const int INF = 1000000000;

struct Entry {
  int x, y, top, first;
  Entry(int x, int y, int t, int f) : x(x), y(y), top(t), first(f) {}
};

int mindist[201][201][20][20];

int main() {
  for (int i = 0; i < 201; ++i) {
    for (int j = 0; j < 201; ++j) {
      for (int k = 0; k < 20; ++k) {
        for (int l = 0; l < 20; ++l) {
          mindist[i][j][k][l] = INF;
        }
      }
    }
  }
  mindist[100][100][0][5] = 0;
  queue<Entry> q;
  q.push(Entry(100, 100, 0, 5));
  while (!q.empty()) {
    Entry e = q.front();
    q.pop();
    int curcost = mindist[e.y][e.x][e.top][e.first];
    int dir = 1 - ((e.x + e.y) & 1);
    for (int i = 0; i < 3; ++i) {
      Dice20 dice(dir, e.top, e.first);
      dice.roll(i);
      int nx = e.x + dx[dir][i], ny = e.y + dy[dir][i];
      int nt = dice.top, nf = dice.first;
      if (curcost < 100 && mindist[ny][nx][nt][nf] == INF) {
        mindist[ny][nx][nt][nf] = curcost + 1;
        q.push(Entry(nx, ny, nt, nf));
      }
    }
  }
  while (true) {
    int gx, gy, gt;
    cin >> gx >> gy >> gt;
    if (gx == 0 && gy == 0 && gt == 0) {
      break;
    }
    gx += 100;
    gy += 100;
    int answer = INF;
    for (int i = 0; i < 20; ++i) {
      answer = min(answer, mindist[gy][gx][gt][i]);
    }
    cout << answer << endl;
  }
  return 0;
}

Error: TLE

Fixed submission:

#include <cassert>
#include <iostream>
#include <map>
#include <queue>

/* development:
 *     /\\  /\\  /\\  /\\  /\\
 *    / 0\\/ 1\\/ 2\\/ 3\\/ 4\\
 *    --------------------
 *   /\\ 5/\\ 6/\\ 7/\\ 8/\\ 9/
 *  /10\\/11\\/12\\/13\\/14\\/
 *  --------------------
 *  \\15/\\16/\\17/\\18/\\19/
 *   \\/  \\/  \\/  \\/  \\/
 *
 * roll / direction (top view)
 *   direction = 0:   direction = 1:
 *     1 /\\ 0             0
 *      /xx\\             ----
 *      ----             \\xx/
 *        2             1 \\/ 2
 */

using namespace std;
typedef pair<int, int> pii;

class Dice20 {

private:
  struct Face3 {
    int index[3];
    Face3(int f = -1, int s = -1, int t = -1) {
      index[0] = f;
      index[1] = s;
      index[2] = t;
    }
    void rotate() {
      int tmp = index[0];
      index[0] = index[1];
      index[1] = index[2];
      index[2] = tmp;
    }
  };
  static map<pii, Face3> TABLE[3];
  static void init_table(int t, int f1, int f2, int f3) {
    Face3 f(f1, f2, f3);
    for (int i = 0; i < 3; ++i) {
      for (int j = 0; j < 3; ++j) {
        TABLE[j].insert(make_pair(pii(t, f.index[j]), f));
      }
      f.rotate();
    }
  }

public:
  int dir, top, first;

  Dice20(int d, int t, int f) : dir(d), top(t), first(f) {
    if (TABLE[0].empty()) {
      for (int i = 0; i < 5; ++i) {
        // 0 - 4
        init_table(i, (i + 1) % 5, (i + 4) % 5, i + 5);
        // 5 - 9
        init_table(i + 5, i, i + 10, 10 + (i + 1) % 5);
        // 10 - 14
        init_table(i + 10, i + 5, 5 + (i + 4) % 5, i + 15);
        // 15 - 19
        init_table(i + 15, i + 10, 15 + (i + 4) % 5, 15 + (i + 1) % 5);
      }
    }
    assert(TABLE[0].find(pii(t, f)) != TABLE[0].end());
  }

  void roll(int f) {
    const Face3 &cur = TABLE[0][pii(top, first)];
    const Face3 &next = TABLE[(f + 1 + dir) % 3][pii(cur.index[f], top)];
    top = cur.index[f];
    first = next.index[0];
    dir = 1 - dir;
  }
  int neighbor(int f) { return TABLE[0][pii(top, first)].index[f]; }
};

map<pii, Dice20::Face3> Dice20::TABLE[3];

const int dx[2][3] = {{-1, 1, 0}, {0, 1, -1}};
const int dy[2][3] = {{0, 0, -1}, {1, 0, 0}};
const int INF = 1000000000;

struct Entry {
  int x, y, top, first;
  Entry(int x, int y, int t, int f) : x(x), y(y), top(t), first(f) {}
};

int mindist[201][201][20][20];

int main() {
  while (true) {
    for (int i = 0; i < 201; ++i) {
      for (int j = 0; j < 201; ++j) {
        for (int k = 0; k < 20; ++k) {
          for (int l = 0; l < 20; ++l) {
            mindist[i][j][k][l] = INF;
          }
        }
      }
    }
    int gx, gy, gt;
    cin >> gx >> gy >> gt;
    if (gx == 0 && gy == 0 && gt == 0) {
      break;
    }
    gx += 100;
    gy += 100;
    mindist[100][100][0][5] = 0;
    queue<Entry> q;
    q.push(Entry(100, 100, 0, 5));
    int answer = INF;
    while (!q.empty()) {
      Entry e = q.front();
      q.pop();
      // cout << e.x << ", " << e.y << ", " << e.top << ", " << e.first << endl;
      int curcost = mindist[e.y][e.x][e.top][e.first];
      if (e.x == gx && e.y == gy && e.top == gt) {
        answer = curcost;
        break;
      }
      int dir = 1 - ((e.x + e.y) & 1);
      for (int i = 0; i < 3; ++i) {
        Dice20 dice(dir, e.top, e.first);
        dice.roll(i);
        int nx = e.x + dx[dir][i], ny = e.y + dy[dir][i];
        int nt = dice.top, nf = dice.first;
        if (mindist[ny][nx][nt][nf] == INF) {
          mindist[ny][nx][nt][nf] = curcost + 1;
          q.push(Entry(nx, ny, nt, nf));
        }
      }
    }
    cout << answer << endl;
  }
  return 0;
}