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

#include <algorithm>
#include <iostream>
#include <queue>
#include <string>
#include <utility>
#include <vector>

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

class Dice {
  int face[6];
  void roll(int a, int b, int c, int d) {
    int tmp = face[a];
    face[a] = face[b];
    face[b] = face[c];
    face[c] = face[d];
    face[d] = tmp;
  }

public:
  static const int TOP = 0, BACK = 1, LEFT = 2;
  static const int FRONT = 3, RIGHT = 4, BOTTOM = 5;
  Dice() {
    for (int i = 0; i < 6; ++i) {
      face[i] = i;
    }
  }
  int operator[](int index) const { return face[index]; }
  void roll_x_inc() { roll(TOP, LEFT, BOTTOM, RIGHT); }
  void roll_x_dec() { roll(TOP, RIGHT, BOTTOM, LEFT); }
  void roll_y_inc() { roll(TOP, BACK, BOTTOM, FRONT); }
  void roll_y_dec() { roll(TOP, FRONT, BOTTOM, BACK); }
  void roll_z_inc() { roll(FRONT, LEFT, BACK, RIGHT); }
  void roll_z_dec() { roll(FRONT, RIGHT, BACK, LEFT); }
  static vector<Dice> enumerate() {
    vector<Dice> ret;
    Dice d;
    for (int i = 0; i < 6; ++i) {
      for (int j = 0; j < 4; ++j) {
        ret.push_back(d);
        d.roll_z_inc();
      }
      if (i & 1) {
        d.roll_y_inc();
      } else {
        d.roll_x_inc();
      }
    }
    return ret;
  }
};

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

bool between(int a, int b, int c) { return a <= b && b < c; }

int cell_dir(char c) {
  switch (c) {
  case '+':
    return 15;
  case '|':
    return 10;
  case '-':
    return 5;
  case '<':
    return 4;
  case '>':
    return 1;
  case '^':
    return 2;
  case 'v':
    return 8;
  }
  return 0;
}

int make_graph(const vector<string> &field, vector<vector<pii>> &conn,
               vector<int> &tops) {
  int H = field.size(), W = field[0].size();
  conn.resize(H * W * 24);
  tops.resize(24);
  vector<vector<int>> roll_table(6, vector<int>(6));
  vector<Dice> dices = Dice::enumerate();
  int start_face = 0;
  for (int i = 0; i < dices.size(); ++i) {
    if (dices[i][Dice::TOP] == 0 && dices[i][Dice::BACK] == 1) {
      start_face = i;
    }
    roll_table[dices[i][Dice::TOP]][dices[i][Dice::FRONT]] = i;
    tops[i] = dices[i][Dice::TOP];
  }
  for (int i = 0; i < H; ++i) {
    for (int j = 0; j < W; ++j) {
      int dir = cell_dir(field[i][j]);
      for (int k = 0; k < 4; ++k) {
        if (!(dir & (1 << k))) {
          continue;
        }
        int nr = i + dy[k], nc = j + dx[k];
        if (!between(0, nr, H) || !between(0, nc, W)) {
          continue;
        }
        for (int l = 0; l < 24; ++l) {
          Dice d = dices[l];
          switch (k) {
          case 0:
            d.roll_x_inc();
            break;
          case 1:
            d.roll_y_dec();
            break;
          case 2:
            d.roll_x_dec();
            break;
          case 3:
            d.roll_y_inc();
            break;
          }
          int nd = roll_table[d[Dice::TOP]][d[Dice::FRONT]];
          int cur = ((i * W) + j) * 24 + l;
          int next = ((nr * W) + nc) * 24 + nd;
          conn[next].push_back(pii(cur, dices[l][Dice::TOP]));
        }
      }
    }
  }
  return start_face;
}

bool is_reachable(const vector<vector<pii>> &conn, int start, int goal) {
  int n = conn.size();
  vector<bool> passed(n);
  queue<int> q;
  q.push(start);
  passed[start] = true;
  while (!q.empty()) {
    int p = q.front();
    if (p == goal) {
      return true;
    }
    q.pop();
    for (int i = 0; i < conn[p].size(); ++i) {
      if (passed[conn[p][i].first]) {
        continue;
      }
      passed[conn[p][i].first] = true;
      q.push(conn[p][i].first);
    }
  }
  return false;
}

int count_reachable(const vector<vector<pii>> &conn, const vector<int> &goals) {
  int n = conn.size();
  vector<bool> passed(n);
  queue<int> q;
  for (int i = 0; i < goals.size(); ++i) {
    passed[goals[i]] = true;
    q.push(goals[i]);
  }
  while (!q.empty()) {
    int p = q.front();
    q.pop();
    for (int i = 0; i < conn[p].size(); ++i) {
      if (passed[conn[p][i].first]) {
        continue;
      }
      passed[conn[p][i].first] = true;
      q.push(conn[p][i].first);
    }
  }
  int answer = 0;
  for (int i = 0; i < n; ++i) {
    if (passed[i]) {
      ++answer;
    }
  }
  return answer;
}

int main() {
  int H, W;
  cin >> H >> W;
  vector<string> field(H);
  for (int i = 0; i < H; ++i) {
    cin >> field[i];
  }
  vector<string> face(6);
  int maxlen = 0;
  for (int i = 0; i < 6; ++i) {
    cin >> face[i];
    maxlen = max(maxlen, (int)face[i].size());
  }
  int Rs, Cs, Rd, Cd;
  cin >> Rs >> Cs >> Rd >> Cd;
  --Rs;
  --Cs;
  --Rd;
  --Cd;
  vector<vector<pii>> conn;
  vector<int> tops;
  int start = make_graph(field, conn, tops);
  start += ((Rs * W) + Cs) * 24;
  vector<int> goals;
  for (int i = 0; i < 24; ++i) {
    int node = ((Rd * W) + Cd) * 24 + i;
    if (is_reachable(conn, node, start)) {
      goals.push_back(node);
    }
  }
  if (goals.size() == 0) {
    cout << "no" << endl;
    return 0;
  }
  int n = conn.size();
  vector<string> mincost(conn.size());
  vector<bool> is_goal(conn.size());
  for (int i = 0; i < goals.size(); ++i) {
    mincost[goals[i]] = face[tops[goals[i] % 24]];
    is_goal[goals[i]] = true;
  }
  int internal_n = count_reachable(conn, goals);
  for (int t = 0; t < internal_n * (maxlen + 1); ++t) {
    vector<string> mc(mincost);
    bool modified = false;
    for (int i = 0; i < n; ++i) {
      if (mincost[i] == "") {
        continue;
      }
      for (int j = 0; j < conn[i].size(); ++j) {
        int from = i, to = conn[i][j].first;
        int top = conn[i][j].second;
        if (mincost[to] == "" || mc[to] > face[top] + mincost[from]) {
          mc[to] = face[top] + mincost[from];
          modified = true;
          if (to == start && t >= internal_n) {
            cout << "infinite" << endl;
            return 0;
          }
        }
      }
    }
    mincost.swap(mc);
    if (!modified) {
      break;
    }
  }
  cout << mincost[start] << endl;
  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <iostream>
#include <queue>
#include <string>
#include <utility>
#include <vector>

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

class Dice {
  int face[6];
  void roll(int a, int b, int c, int d) {
    int tmp = face[a];
    face[a] = face[b];
    face[b] = face[c];
    face[c] = face[d];
    face[d] = tmp;
  }

public:
  static const int TOP = 0, BACK = 1, LEFT = 2;
  static const int FRONT = 3, RIGHT = 4, BOTTOM = 5;
  Dice() {
    for (int i = 0; i < 6; ++i) {
      face[i] = i;
    }
  }
  int operator[](int index) const { return face[index]; }
  void roll_x_inc() { roll(TOP, LEFT, BOTTOM, RIGHT); }
  void roll_x_dec() { roll(TOP, RIGHT, BOTTOM, LEFT); }
  void roll_y_inc() { roll(TOP, BACK, BOTTOM, FRONT); }
  void roll_y_dec() { roll(TOP, FRONT, BOTTOM, BACK); }
  void roll_z_inc() { roll(FRONT, LEFT, BACK, RIGHT); }
  void roll_z_dec() { roll(FRONT, RIGHT, BACK, LEFT); }
  static vector<Dice> enumerate() {
    vector<Dice> ret;
    Dice d;
    for (int i = 0; i < 6; ++i) {
      for (int j = 0; j < 4; ++j) {
        ret.push_back(d);
        d.roll_z_inc();
      }
      if (i & 1) {
        d.roll_y_inc();
      } else {
        d.roll_x_inc();
      }
    }
    return ret;
  }
};

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

bool between(int a, int b, int c) { return a <= b && b < c; }

int cell_dir(char c) {
  switch (c) {
  case '+':
    return 15;
  case '|':
    return 10;
  case '-':
    return 5;
  case '<':
    return 4;
  case '>':
    return 1;
  case '^':
    return 2;
  case 'v':
    return 8;
  }
  return 0;
}

int make_graph(const vector<string> &field, vector<vector<pii>> &conn,
               vector<int> &tops) {
  int H = field.size(), W = field[0].size();
  conn.resize(H * W * 24);
  tops.resize(24);
  vector<vector<int>> roll_table(6, vector<int>(6));
  vector<Dice> dices = Dice::enumerate();
  int start_face = 0;
  for (int i = 0; i < dices.size(); ++i) {
    if (dices[i][Dice::TOP] == 0 && dices[i][Dice::BACK] == 1) {
      start_face = i;
    }
    roll_table[dices[i][Dice::TOP]][dices[i][Dice::FRONT]] = i;
    tops[i] = dices[i][Dice::TOP];
  }
  for (int i = 0; i < H; ++i) {
    for (int j = 0; j < W; ++j) {
      int dir = cell_dir(field[i][j]);
      for (int k = 0; k < 4; ++k) {
        if (!(dir & (1 << k))) {
          continue;
        }
        int nr = i + dy[k], nc = j + dx[k];
        if (!between(0, nr, H) || !between(0, nc, W)) {
          continue;
        }
        for (int l = 0; l < 24; ++l) {
          Dice d = dices[l];
          switch (k) {
          case 0:
            d.roll_x_inc();
            break;
          case 1:
            d.roll_y_dec();
            break;
          case 2:
            d.roll_x_dec();
            break;
          case 3:
            d.roll_y_inc();
            break;
          }
          int nd = roll_table[d[Dice::TOP]][d[Dice::FRONT]];
          int cur = ((i * W) + j) * 24 + l;
          int next = ((nr * W) + nc) * 24 + nd;
          // conn[cur].push_back(pii(next, d[Dice::TOP]));
          conn[next].push_back(pii(cur, dices[l][Dice::TOP]));
        }
      }
    }
  }
  return start_face;
}

bool is_reachable(const vector<vector<pii>> &conn, int start, int goal) {
  int n = conn.size();
  vector<bool> passed(n);
  queue<int> q;
  q.push(start);
  passed[start] = true;
  while (!q.empty()) {
    int p = q.front();
    if (p == goal) {
      return true;
    }
    q.pop();
    for (int i = 0; i < conn[p].size(); ++i) {
      if (passed[conn[p][i].first]) {
        continue;
      }
      passed[conn[p][i].first] = true;
      q.push(conn[p][i].first);
    }
  }
  return false;
}

int count_reachable(const vector<vector<pii>> &conn, const vector<int> &goals) {
  int n = conn.size();
  vector<bool> passed(n);
  queue<int> q;
  for (int i = 0; i < goals.size(); ++i) {
    passed[goals[i]] = true;
    q.push(goals[i]);
  }
  while (!q.empty()) {
    int p = q.front();
    q.pop();
    for (int i = 0; i < conn[p].size(); ++i) {
      if (passed[conn[p][i].first]) {
        continue;
      }
      passed[conn[p][i].first] = true;
      q.push(conn[p][i].first);
    }
  }
  int answer = 0;
  for (int i = 0; i < n; ++i) {
    if (passed[i]) {
      ++answer;
    }
  }
  return answer;
}

int main() {
  int H, W;
  cin >> H >> W;
  vector<string> field(H);
  for (int i = 0; i < H; ++i) {
    cin >> field[i];
  }
  vector<string> face(6);
  int maxlen = 0;
  for (int i = 0; i < 6; ++i) {
    cin >> face[i];
    maxlen = max(maxlen, (int)face[i].size());
  }
  int Rs, Cs, Rd, Cd;
  cin >> Rs >> Cs >> Rd >> Cd;
  --Rs;
  --Cs;
  --Rd;
  --Cd;
  vector<vector<pii>> conn;
  vector<int> tops;
  int start = make_graph(field, conn, tops);
  start += ((Rs * W) + Cs) * 24;
  vector<int> goals;
  for (int i = 0; i < 24; ++i) {
    int node = ((Rd * W) + Cd) * 24 + i;
    if (is_reachable(conn, node, start)) {
      goals.push_back(node);
    }
  }
  if (goals.size() == 0) {
    cout << "no" << endl;
    return 0;
  }
  int n = conn.size();
  vector<string> mincost(conn.size());
  // vector<bool> modified(conn.size());
  vector<bool> is_goal(conn.size());
  for (int i = 0; i < goals.size(); ++i) {
    mincost[goals[i]] = face[tops[goals[i] % 24]];
    is_goal[goals[i]] = true;
    // modified[goals[i]] = true;
  }
  int internal_n = count_reachable(conn, goals);
  for (int t = 0; t < internal_n * (maxlen + 1); ++t) {
    vector<string> mc(mincost);
    // vector<bool> mod(conn.size());
    for (int i = 0; i < n; ++i) {
      if (mincost[i] == "") {
        continue;
      }
      for (int j = 0; j < conn[i].size(); ++j) {
        int from = i, to = conn[i][j].first;
        int top = conn[i][j].second;
        if (mincost[to] == "" || mc[to] > face[top] + mincost[from]) {
          mc[to] = face[top] + mincost[from];
          // mod[to] = true;
          if (to == start && t >= internal_n) {
            cout << "infinite" << endl;
            return 0;
          }
        }
      }
    }
    mincost.swap(mc);
    // modified.swap(mod);
  }
  cout << mincost[start] << endl;
  return 0;
}