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

#include <bits/stdc++.h>
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;

int H, W, K;
int POW[13];
int dp[50][50][4][4096]; // dp[row][col][Kの残数][過去6回の移動ログ] = 最大値
char base_map[50][51];

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

int recursive(
    int row, int col, int back_count, int move_log,
    int moved_count) { // moved_log[]:インデックスが小さいほど新しい(右シフト)

  if (dp[row][col][back_count][move_log] != -1)
    return dp[row][col][back_count][move_log]; // 計算済ならreturn

  if (row == H - 1 && col == W - 1 && back_count == K)
    return 0;

  int result_E = 0, result_S = 0, result_W = 0, result_N = 0;
  bool visited_E = false, visited_S = false, visited_W = false,
       visited_N = false;

  // 過去の移動ログから、訪問済のマス情報を特定する
  int tmp_row = row, tmp_col = col;

  int log_array[6], tmp_log;

  tmp_log = move_log;
  for (int i = 0; i < 6; i++) {
    log_array[i] = tmp_log % 4;
    tmp_log /= 4;
  }

  for (int i = 0; i < min(6, moved_count); i++) {
    switch (log_array[i]) { // ログを打ち消す方向に動く
    case 0:                 // East
      tmp_col--;
      break;
    case 1: // South
      tmp_row--;
      break;
    case 2: // West
      tmp_col++;
      break;
    case 3: // North
      tmp_row++;
      break;
    }

    if (tmp_row == row && tmp_col == col + 1) { // 右のマスと一致
      visited_E = true;
    } else if (tmp_row == row + 1 && tmp_col == col) { // 下のマスと一致
      visited_S = true;
    } else if (tmp_row == row && tmp_col == col - 1) { // 左のマスと一致
      visited_W = true;
    } else if (tmp_row == row - 1 && tmp_col == col) { // 上のマスと一致
      visited_N = true;
    }
  }

  int next_log = move_log % 1024;
  int ret = -BIG_NUM;

  // 右へ
  if (rangeCheck(row, col + 1) == true && base_map[row][col + 1] != '#') {
    if (visited_E == false) {
      result_E += base_map[row][col + 1] - '0';
    }
    int next_code = 4 * next_log + 0;
    result_E += recursive(row, col + 1, back_count, next_code, moved_count + 1);
    ret = max(ret, result_E);
  }

  // 下へ
  if (rangeCheck(row + 1, col) == true && base_map[row + 1][col] != '#') {
    if (visited_S == false) {
      result_S += base_map[row + 1][col] - '0';
    }
    int next_code = 4 * next_log + 1;
    result_S += recursive(row + 1, col, back_count, next_code, moved_count + 1);
    ret = max(ret, result_S);
  }

  // 左へ
  if (back_count < K && rangeCheck(row, col - 1) == true &&
      base_map[row][col - 1] != '#') {
    if (visited_W == false) {
      result_W += base_map[row][col - 1] - '0';
    }
    int next_code = 4 * next_log + 2;
    result_W +=
        recursive(row, col - 1, back_count + 1, next_code, moved_count + 1);
    ret = max(ret, result_W);
  }

  // 上へ
  if (back_count < K && rangeCheck(row - 1, col) == true &&
      base_map[row - 1][col] != '#') {
    if (visited_N == false) {
      result_N += base_map[row - 1][col] - '0';
    }
    int next_code = 4 * next_log + 3;
    result_N +=
        recursive(row - 1, col, back_count + 1, next_code, moved_count + 1);
    ret = max(ret, result_N);
  }

  return dp[row][col][back_count][move_log] = ret;
}

int main() {

  for (int i = 0; i < 13; i++)
    POW[i] = pow(2, i);

  scanf("%d %d %d", &H, &W, &K);

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

  for (int row = 0; row < H; row++) {
    for (int col = 0; col < W; col++) {
      for (int i = 0; i <= 3; i++) {
        for (int state = 0; state < POW[12]; state++)
          dp[row][col][i][state] = -1;
      }
    }
  }

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

  return 0;
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>
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 Type {
  East,
  South,
  West,
  North,
};

struct Info {
  void set(int arg_row, int arg_col, int arg_back_count, int arg_moved_count,
           int arg_sum, int arg_move_log) {
    row = arg_row;
    col = arg_col;
    back_count = arg_back_count;
    moved_count = arg_moved_count;
    sum = arg_sum;
    move_log = arg_move_log;
  }
  bool operator<(const struct Info &arg) const { // 総和の降順(PQ)
    return sum > arg.sum;
  }

  int row, col, back_count, moved_count, sum, move_log;
};

int H, W, K;
int POW[7];
int dp[50][50][4]
      [4096]; // dp[row][col][Kの残数][moved_count][過去6回の移動ログ] = 最大値
char base_map[50][51];

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

int makeCode(Type move_log[6]) {

  int ret = 0;

  for (int i = 0; i < 6; i++) {
    ret += move_log[i] * POW[i];
  }

  return ret;
}

bool is_num(int row, int col) {
  return base_map[row][col] >= '1' &&
         base_map[row][col] <= '9'; // 0の土産物屋はない
}

int main() {

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

  scanf("%d %d %d", &H, &W, &K);

  for (int row = 0; row < H; row++) {
    scanf("%s", base_map[row]);
  }

  for (int row = 0; row < H; row++) {
    for (int col = 0; col < W; col++) {
      for (int i = 0; i <= K; i++) {
        for (int state = 0; state < POW[6]; state++)
          dp[row][col][i][state] = -1;
      }
    }
  }

  priority_queue<Info> Q;
  Info first;
  first.set(0, 0, 0, 0, 0, 0);

  dp[0][0][0][0] = 0;

  int bit_mask = 4095;

  Q.push(first);

  int log_array[6], tmp_log;

  Info info;
  while (!Q.empty()) {
    info = Q.top();
    Q.pop();

    if (dp[info.row][info.col][info.back_count][info.move_log] > info.sum)
      continue;

    int result_E = 0, result_S = 0, result_W = 0, result_N = 0;
    bool visited_E = false, visited_S = false, visited_W = false,
         visited_N = false;

    // 過去の移動ログから、訪問済のマス情報を特定する
    int tmp_row = info.row, tmp_col = info.col;

    tmp_log = info.move_log;
    // printf("tmp_log:%d\\n",tmp_log);
    for (int i = 0; i < 6; i++) {
      log_array[i] = tmp_log & 3;
      // printf("array[%d]:%d\\n",i,log_array[i]);
      tmp_log /= 4;
    }

    for (int i = 0; i < min(6, info.moved_count); i++) {
      switch (log_array[i]) { // ログを打ち消す方向に動く
      case 0:
        tmp_col--;
        break;
      case 1:
        tmp_row--;
        break;
      case 2:
        tmp_col++;
        break;
      case 3:
        tmp_row++;
        break;
      }

      if (tmp_row == info.row && tmp_col == info.col + 1) { // 右のマスと一致
        visited_E = true;
      } else if (tmp_row == info.row + 1 &&
                 tmp_col == info.col) { // 下のマスと一致
        visited_S = true;
      } else if (tmp_row == info.row &&
                 tmp_col == info.col - 1) { // 左のマスと一致
        visited_W = true;
      } else if (tmp_row == info.row - 1 &&
                 tmp_col == info.col) { // 上のマスと一致
        visited_N = true;
      }
    }

    // 次の移動ログを作る

    // 右へ
    if (rangeCheck(info.row, info.col + 1) == true &&
        base_map[info.row][info.col + 1] != '#') {
      if (visited_E == false && is_num(info.row, info.col + 1) == true) {
        result_E += base_map[info.row][info.col + 1] - '0';
      }
      int next_code = ((info.move_log << 2) & bit_mask) | 0;
      if (dp[info.row][info.col + 1][info.back_count][next_code] <
          info.sum + result_E) {
        dp[info.row][info.col + 1][info.back_count][next_code] =
            info.sum + result_E;
        Info next;
        next.set(info.row, info.col + 1, info.back_count, info.moved_count + 1,
                 info.sum + result_E, next_code);
        Q.push(next);
      }
    }

    // 下へ
    if (rangeCheck(info.row + 1, info.col) == true &&
        base_map[info.row + 1][info.col] != '#') {
      if (visited_S == false && is_num(info.row + 1, info.col) == true) {
        result_S += base_map[info.row + 1][info.col] - '0';
      }
      int next_code = ((info.move_log << 2) & bit_mask) | 1;
      if (dp[info.row + 1][info.col][info.back_count][next_code] <
          info.sum + result_S) {
        dp[info.row + 1][info.col][info.back_count][next_code] =
            info.sum + result_S;
        Info next;
        next.set(info.row + 1, info.col, info.back_count, info.moved_count + 1,
                 info.sum + result_S, next_code);
        Q.push(next);
      }
    }

    if (info.back_count == K)
      continue;

    // 左へ
    if (rangeCheck(info.row, info.col - 1) == true &&
        base_map[info.row][info.col - 1] != '#') {
      if (visited_W == false && is_num(info.row, info.col - 1) == true) {
        result_W += base_map[info.row][info.col - 1] - '0';
      }
      int next_code = ((info.move_log << 2) & bit_mask) | 2;
      if (dp[info.row][info.col - 1][info.back_count + 1][next_code] <
          info.sum + result_W) {
        dp[info.row][info.col - 1][info.back_count + 1][next_code] =
            info.sum + result_W;
        Info next;
        next.set(info.row, info.col - 1, info.back_count + 1,
                 info.moved_count + 1, info.sum + result_W, next_code);
        Q.push(next);
      }
    }

    // 上へ
    if (rangeCheck(info.row - 1, info.col) == true &&
        base_map[info.row - 1][info.col] != '#') {
      if (visited_N == false && is_num(info.row - 1, info.col) == true) {
        result_N += base_map[info.row - 1][info.col] - '0';
      }
      int next_code = ((info.move_log << 2) & bit_mask) | 3;
      if (dp[info.row - 1][info.col][info.back_count + 1][next_code] <
          info.sum + result_N) {
        dp[info.row - 1][info.col][info.back_count + 1][next_code] =
            info.sum + result_N;
        Info next;
        next.set(info.row - 1, info.col, info.back_count + 1,
                 info.moved_count + 1, info.sum + result_N, next_code);
        Q.push(next);
      }
    }
  }

  int ans = 0;
  for (int state = 0; state < POW[6]; state++) {
    for (int count = 4; count <= 6; count++) {
      ans = max(ans, dp[H - 1][W - 1][K][state]);
    }
  }

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

  return 0;
}