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

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

enum DIR {
  North,
  East,
  South,
  West,
};

struct Node {
  int num, parent_id, children[4], suffix_link, depth;
  bool finish_FLG;
  DIR pattern[10];
};

struct Data {
  void set(int arg_row, int arg_col) {
    row = arg_row;
    col = arg_col;
  }
  int row, col;
};

struct Info {
  Info(int arg_row, int arg_col, int arg_sum_cost, int arg_node_loc) {
    row = arg_row;
    col = arg_col;
    sum_cost = arg_sum_cost;
    node_loc = arg_node_loc;
  }
  bool operator<(const struct Info &arg) const {
    return sum_cost > arg.sum_cost;
  }
  int row, col, sum_cost, node_loc;
};

int H, W, POW[11];
int diff_row[4] = {-1, 0, 0, 1}, diff_col[4] = {0, -1, 1, 0};
int table[128], min_cost[50][50][200];
DIR dir_table[4] = {North, East, South, West};

char base_map[50][51];
Node nodes[200];
Data start, goal;
map<int, int> MAP;

bool rangeCheck(int row, int col) {
  if (row >= 0 && row <= H - 1 && col >= 0 && col <= W - 1)
    return true;
  else {
    return false;
  }
}

void debug(DIR dir) {

  switch (dir) {
  case North:
    printf("U");
    break;
  case East:
    printf("R");
    break;
  case South:
    printf("D");
    break;
  case West:
    printf("L");
    break;
  }
}

void func() {

  for (int i = 0; i < 200; i++) {
    nodes[i].finish_FLG = false;
    for (int k = 0; k < 4; k++)
      nodes[i].children[k] = -1;
  }

  for (int row = 0; row < H; row++) {
    scanf("%s", base_map[row]);
    for (int col = 0; col < W; col++) {
      if (base_map[row][col] == 'S') {

        start.set(row, col);

      } else if (base_map[row][col] == 'G') {

        goal.set(row, col);
      }
    }
  }

  int P;
  scanf("%d", &P);

  nodes[0].parent_id = -1;
  nodes[0].num = 0;
  nodes[0].depth = 0;
  int node_index = 1, tmp_ch, tmp_loc, parent_id, tmp_index;
  char buf[11];
  MAP.clear();

  for (int loop = 0; loop < P; loop++) {

    scanf("%s", buf);

    tmp_index = 0;
    tmp_ch = table[buf[tmp_index]];

    tmp_loc = 0;
    tmp_index = 0;

    while (true) {

      parent_id = tmp_loc;

      if (nodes[tmp_loc].children[tmp_ch] == -1) {

        nodes[tmp_loc].children[tmp_ch] = node_index++;
      }

      tmp_loc = nodes[tmp_loc].children[tmp_ch];

      nodes[tmp_loc].parent_id = parent_id;

      for (int i = 0; i < nodes[parent_id].depth; i++) {
        nodes[tmp_loc].pattern[i] = nodes[parent_id].pattern[i];
      }
      nodes[tmp_loc].pattern[nodes[parent_id].depth] = dir_table[tmp_ch];
      nodes[tmp_loc].depth = nodes[parent_id].depth + 1;

      tmp_index++;

      nodes[tmp_loc].num = -1;
      for (int i = 0; i < nodes[tmp_loc].depth; i++) {
        nodes[tmp_loc].num += (nodes[tmp_loc].pattern[i] + 1) * POW[i];
      }

      MAP[nodes[tmp_loc].num] = tmp_loc;

      if (buf[tmp_index] == '\\0') {
        nodes[tmp_loc].finish_FLG = true;

        break;
      }
      tmp_ch = table[buf[tmp_index]];
    }
  }

  int tmp, start_pos;
  bool Found;

  for (int i = 1; i < node_index; i++) {

    Found = false;
    start_pos = 1;

    while (start_pos < nodes[i].depth) {

      tmp = -1;
      for (int k = start_pos; k < nodes[i].depth; k++) {
        tmp += (nodes[i].pattern[k] + 1) * POW[k - start_pos];
      }

      auto at = MAP.find(tmp);
      if (at != MAP.end()) {
        Found = true;
        break;
      }
      start_pos++;
    }

    if (!Found) {
      nodes[i].suffix_link = 0;
    } else {

      nodes[i].suffix_link = MAP[tmp];
    }
  }

  for (int row = 0; row < H; row++) {
    for (int col = 0; col < W; col++) {
      for (int node_loc = 0; node_loc < node_index; node_loc++)
        min_cost[row][col][node_loc] = BIG_NUM;
    }
  }

  min_cost[start.row][start.col][0] = 0;

  priority_queue<Info> Q;
  Q.push(Info(start.row, start.col, 0, 0));

  int next_node_pos, adj_row, adj_col;
  DIR next_dir;

  bool FLG;

  int calc;

  while (!Q.empty()) {

    if (Q.top().row == goal.row && Q.top().col == goal.col) {

      printf("%d\\n", Q.top().sum_cost);
      return;

    } else if (Q.top().sum_cost >
               min_cost[Q.top().row][Q.top().col][Q.top().node_loc]) {
      Q.pop();
    } else {

      for (int i = 0; i < 4; i++) {
        adj_row = Q.top().row + diff_row[i];
        adj_col = Q.top().col + diff_col[i];

        if (rangeCheck(adj_row, adj_col) == false ||
            base_map[adj_row][adj_col] == '#')
          continue;

        switch (i) {
        case 0:
          next_dir = North;
          break;
        case 1:
          next_dir = West;
          break;
        case 2:
          next_dir = East;
          break;
        case 3:
          next_dir = South;
          break;
        }

        if (nodes[Q.top().node_loc].children[next_dir] != -1) {

          next_node_pos = nodes[Q.top().node_loc].children[next_dir];

        } else {

          if (Q.top().node_loc == 0) {

            next_node_pos = 0;

            if (min_cost[adj_row][adj_col][next_node_pos] >
                Q.top().sum_cost + 1) {
              min_cost[adj_row][adj_col][next_node_pos] = Q.top().sum_cost + 1;
              Q.push(
                  Info(adj_row, adj_col, Q.top().sum_cost + 1, next_node_pos));
            }

            continue;
          }

          tmp = nodes[Q.top().node_loc].suffix_link;

          while (tmp != 0 && nodes[tmp].children[next_dir] == -1) {
            tmp = nodes[tmp].suffix_link;
          }

          if (tmp == 0) {
            if (nodes[tmp].children[next_dir] == -1) {
              next_node_pos = 0;
            } else {
              next_node_pos = nodes[tmp].children[next_dir];
            }

          } else {
            next_node_pos = nodes[tmp].children[next_dir];
          }
        }

        FLG = true;

        tmp = next_node_pos;

        while (tmp != 0) {
          if (nodes[tmp].finish_FLG) {

            FLG = false;
            break;
          }
          tmp = nodes[tmp].suffix_link;
        }

        if (!FLG)
          continue;

        if (min_cost[adj_row][adj_col][next_node_pos] > Q.top().sum_cost + 1) {
          min_cost[adj_row][adj_col][next_node_pos] = Q.top().sum_cost + 1;
          Q.push(Info(adj_row, adj_col, Q.top().sum_cost + 1, next_node_pos));
        }
      }
      Q.pop();
    }
  }
  printf("-1\\n");
}

int main() {

  for (int i = 0; i < 11; i++)
    POW[i] = pow(4, i);

  table['U'] = North;
  table['R'] = East;
  table['D'] = South;
  table['L'] = West;

  while (true) {
    scanf("%d %d", &H, &W);
    if (H == 0 && W == 0)
      break;

    func();
  }
  return 0;
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

enum DIR {
  North,
  East,
  South,
  West,
};

struct Node {
  int num, parent_id, children[4], suffix_link, depth;
  bool finish_FLG;
  DIR pattern[10];
};

struct Data {
  void set(int arg_row, int arg_col) {
    row = arg_row;
    col = arg_col;
  }
  int row, col;
};

struct Info {
  Info(int arg_row, int arg_col, int arg_sum_cost, int arg_node_loc) {
    row = arg_row;
    col = arg_col;
    sum_cost = arg_sum_cost;
    node_loc = arg_node_loc;
  }
  bool operator<(const struct Info &arg) const {
    return sum_cost > arg.sum_cost;
  }
  int row, col, sum_cost, node_loc;
};

int H, W, POW[11];
int diff_row[4] = {-1, 0, 0, 1}, diff_col[4] = {0, -1, 1, 0};
int table[128], min_cost[50][50][200];
DIR dir_table[4] = {North, East, South, West};

char base_map[50][51];
Node nodes[200];
Data start, goal;
map<int, int> MAP;

bool rangeCheck(int row, int col) {
  if (row >= 0 && row <= H - 1 && col >= 0 && col <= W - 1)
    return true;
  else {
    return false;
  }
}

void debug(DIR dir) {

  switch (dir) {
  case North:
    printf("U");
    break;
  case East:
    printf("R");
    break;
  case South:
    printf("D");
    break;
  case West:
    printf("L");
    break;
  }
}

void func() {

  for (int i = 0; i < 200; i++) {
    nodes[i].finish_FLG = false;
    for (int k = 0; k < 4; k++)
      nodes[i].children[k] = -1;
  }

  for (int row = 0; row < H; row++) {
    scanf("%s", base_map[row]);
    for (int col = 0; col < W; col++) {
      if (base_map[row][col] == 'S') {

        start.set(row, col);

      } else if (base_map[row][col] == 'G') {

        goal.set(row, col);
      }
    }
  }

  int P;
  scanf("%d", &P);

  nodes[0].parent_id = -1;
  nodes[0].num = 0;
  nodes[0].depth = 0;
  int node_index = 1, tmp_ch, tmp_loc, parent_id, tmp_index;
  char buf[11];
  MAP.clear();

  // トライ木を構成する
  for (int loop = 0; loop < P; loop++) {

    // printf("\\nloop:%d\\n",loop);

    scanf("%s", buf);

    tmp_index = 0;
    tmp_ch = table[buf[tmp_index]];

    tmp_loc = 0;
    tmp_index = 0;

    while (true) {

      parent_id = tmp_loc;

      if (nodes[tmp_loc].children[tmp_ch] == -1) {

        nodes[tmp_loc].children[tmp_ch] = node_index++;
      }
      // 小ノードに移動
      tmp_loc = nodes[tmp_loc].children[tmp_ch];

      /*	printf("tmp_loc:%d\\n",tmp_loc);
              debug(dir_table[tmp_ch]);
              printf("\\n");*/

      nodes[tmp_loc].parent_id = parent_id;
      // 文字列をコピー&追加
      for (int i = 0; i < nodes[parent_id].depth; i++) {
        nodes[tmp_loc].pattern[i] = nodes[parent_id].pattern[i];
      }
      nodes[tmp_loc].pattern[nodes[parent_id].depth] = dir_table[tmp_ch];
      nodes[tmp_loc].depth = nodes[parent_id].depth + 1;

      tmp_index++;

      // 配列をコード化
      nodes[tmp_loc].num = -1;
      for (int i = 0; i < nodes[tmp_loc].depth; i++) {
        nodes[tmp_loc].num +=
            (nodes[tmp_loc].pattern[i] + 1) * POW[i]; // ★ハマりpoint★
      }
      // printf("num:%d\\n",nodes[tmp_loc].num);
      MAP[nodes[tmp_loc].num] = tmp_loc;

      if (buf[tmp_index] == '\\0') {
        nodes[tmp_loc].finish_FLG = true;
        // printf("%dにてfinish\\n",tmp_loc);

        break;
      }
      tmp_ch = table[buf[tmp_index]];
    }
  }

  int tmp, start_pos;
  bool Found;

  // printf("\\n");

  // サフィックスリンクを張る
  for (int i = 1; i < node_index; i++) {

    /*printf("nodes[%d] ",i);
    for(int k = 0; k < nodes[i].depth; k++){
            debug(nodes[i].pattern[k]);
    }
    printf("\\n");*/

    Found = false;
    start_pos = 1;
    // 遷移できる場所を探す
    while (start_pos < nodes[i].depth) {

      // printf("start_pos:%d\\n",start_pos);

      tmp = -1;
      for (int k = start_pos; k < nodes[i].depth; k++) {
        tmp += (nodes[i].pattern[k] + 1) * POW[k - start_pos];
      }

      // printf("tmp:%d\\n",tmp);

      auto at = MAP.find(tmp);
      if (at != MAP.end()) {
        Found = true;
        break;
      }
      start_pos++;
    }

    if (!Found) { // 接続できるノードがないので、ルートノードに貼る
      // printf("原点にsuffix_linkを張った\\n");
      nodes[i].suffix_link = 0;
    } else {
      // printf("%dにsuffix_linkを張った\\n",MAP[tmp]);
      nodes[i].suffix_link = MAP[tmp];
    }
  }

  for (int row = 0; row < H; row++) {
    for (int col = 0; col < W; col++) {
      for (int node_loc = 0; node_loc < node_index; node_loc++)
        min_cost[row][col][node_loc] = BIG_NUM;
    }
  }

  min_cost[start.row][start.col][0] = 0;

  priority_queue<Info> Q;
  Q.push(Info(start.row, start.col, 0, 0));

  int next_node_pos, adj_row, adj_col;
  DIR next_dir;

  bool FLG;

  int calc;

  while (!Q.empty()) {

    if (Q.top().row == goal.row && Q.top().col == goal.col) {

      printf(
          "%d\\n",
          Q.top()
              .sum_cost); // Qをコストの小さい順に回しているから、最速でゴールするデータは最速で遷移してくるはず
      return;

    } else if (Q.top().sum_cost >
               min_cost[Q.top().row][Q.top().col][Q.top().node_loc]) {
      Q.pop();
    } else {

      for (int i = 0; i < 4; i++) {
        adj_row = Q.top().row + diff_row[i];
        adj_col = Q.top().col + diff_col[i];

        if (rangeCheck(adj_row, adj_col) == false ||
            base_map[adj_row][adj_col] == '#')
          continue;

        switch (i) {
        case 0:
          next_dir = North;
          break;
        case 1:
          next_dir = West;
          break;
        case 2:
          next_dir = East;
          break;
        case 3:
          next_dir = South;
          break;
        }

        // printf("現在:(%d,%d)
        // next:(%d,%d)\\n",Q.top().row,Q.top().col,adj_row,adj_col);
        /*debug(next_dir);
        printf("\\n");*/

        if (nodes[Q.top().node_loc].children[next_dir] != -1) { // 子に遷移できる

          // printf("子に遷移できる\\n");

          next_node_pos = nodes[Q.top().node_loc].children[next_dir];

        } else { // 行き止まり

          // printf("行き止まり\\n");

          if (Q.top().node_loc == 0) { // 原点の場合<suffix_linkが未定義>

            next_node_pos = 0;

            if (min_cost[adj_row][adj_col][next_node_pos] >
                Q.top().sum_cost + 1) {
              min_cost[adj_row][adj_col][next_node_pos] = Q.top().sum_cost + 1;
              Q.push(
                  Info(adj_row, adj_col, Q.top().sum_cost + 1, next_node_pos));
            }

            continue;
          }

          tmp = nodes[Q.top().node_loc].suffix_link;

          // suffix_link先の安全性を確かめる
          FLG = true;

          calc = tmp;
          ;

          while (calc != 0) {
            if (nodes[calc].finish_FLG) {
              // printf("nodes[%d]でfinish_FLG\\n",tmp);
              FLG = false;
              break;
            }
            tmp = nodes[calc].suffix_link;
          }

          if (!FLG)
            continue; // 禁止パターンに抵触

          while (FLG) {

            if (tmp == 0) { // 原点に戻った場合
              if (nodes[0].children[next_dir] == -1) { // trie木にない文字の場合
                next_node_pos = 0;
              } else {
                next_node_pos = nodes[0].children[next_dir];
              }
              break;
            } else {
              if (nodes[tmp].pattern[nodes[tmp].depth - 1] ==
                  next_dir) { // 文字の末尾が、今回のdirと一致している場合 (abc
                              // で,dが来て、bc→bcd or (bc)-c-
                              // cdに遷移する場合など)
                next_node_pos = tmp;
                break;
              } else {
                if (nodes[tmp].children[next_dir] ==
                    -1) { // suffix_link先にも該当する子への分岐がない

                  calc = tmp;
                  ;

                  while (calc != 0) {
                    if (nodes[calc].finish_FLG) {
                      // printf("nodes[%d]でfinish_FLG\\n",tmp);
                      FLG = false;
                      break;
                    }
                    tmp = nodes[calc].suffix_link;
                  }

                  if (!FLG)
                    break;

                  tmp = nodes[tmp].suffix_link;
                } else {
                  next_node_pos = nodes[tmp].children[next_dir];
                  break;
                }
              }
            }
          }
          if (!FLG)
            continue; // 途中でパターンを踏んだらcontinue
        }

        // 遷移先、およびそのsiffix_link列の中にfinish_FLGがtrueになっているものがないか調べる
        tmp = next_node_pos;

        // printf("next_node_pos:%d\\n",next_node_pos);

        while (tmp != 0) {
          if (nodes[tmp].finish_FLG) {
            // printf("nodes[%d]でfinish_FLG\\n",tmp);
            FLG = false;
            break;
          }
          tmp = nodes[tmp].suffix_link;
        }

        if (!FLG)
          continue; // 禁止パターンに抵触

        if (min_cost[adj_row][adj_col][next_node_pos] > Q.top().sum_cost + 1) {
          min_cost[adj_row][adj_col][next_node_pos] = Q.top().sum_cost + 1;
          Q.push(Info(adj_row, adj_col, Q.top().sum_cost + 1, next_node_pos));
        }
      }
      Q.pop();
    }
  }
  printf("-1\\n");
}

int main() {

  for (int i = 0; i < 11; i++)
    POW[i] = pow(4, i);

  table['U'] = North;
  table['R'] = East;
  table['D'] = South;
  table['L'] = West;

  while (true) {
    scanf("%d %d", &H, &W);
    if (H == 0 && W == 0)
      break;

    func();
  }
  return 0;
}