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


//

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 2147483647;
// const ll INF = 9223372036854775807;
// const ll MOD = 1e9 + 7;

char field[1000][1000];
int step[1000][1000]; // INFは未訪問

struct Loc {
  int r;
  int c;
};

// 移動ベクトル
vector<int> dr;
vector<int> dc;
map<int, int> mv_to_cost;

// sr: スタート行, cs: スタート列, gr: ゴール行, gc: ゴール列
int bfs(int R, int C, int sr, int sc, int gr, int gc) {
  // 未訪問で初期化
  for (int r = 0; r < R; r++) {
    for (int c = 0; c < C; c++) {
      step[r][c] = INF;
    }
  }

  deque<Loc> search_queue;
  search_queue.push_back(Loc{sr, sc});
  step[sr][sc] = 0;

  while (!search_queue.empty()) {
    // キューから探索対象の位置情報を取り出す
    Loc loc = search_queue.front();
    search_queue.pop_front();

    int r = loc.r;
    int c = loc.c;
    int s = step[r][c];
    // cout << r << ' ' << c << " (" << s << ")" << endl; // **** debug ****

    if (r == gr && c == gc)
      return s; // ゴールに到達

    // 探索を予約
    for (int mv = 0; mv < dr.size(); mv++) {
      int next_r = r + dr[mv];
      int next_c = c + dc[mv];

      if (next_r < 0 || next_r >= R || next_c < 0 || next_c >= C)
        continue; // 外壁がない場合
      if (field[next_r][next_c] == '#')
        continue; // 壁

      int cost = mv_to_cost[mv];
      if (step[next_r][next_c] <= s + cost)
        continue; // 同等以下のコストで探索済み

      if (cost == 0) {
        search_queue.push_front(Loc{next_r, next_c});
      } else {
        search_queue.push_back(Loc{next_r, next_c});
      }

      step[next_r][next_c] = s + cost;
    }
  }

  return -1; // ゴールできなかった場合
}

int main() {
  int R, C;
  int sr, sc, gr, gc;
  cin >> R >> C;
  cin >> sr >> sc;
  cin >> gr >> gc;

  for (int r = 0; r < R; r++) {
    for (int c = 0; c < C; c++) {
      cin >> field[r][c];
    }
  }

  // 移動ベクトルを作成
  int mv = 0;
  for (int i = -2; i <= 2; i++) {
    for (int j = -2; j <= 2; j++) {
      if (i == 0 && j == 0)
        continue;
      dr.push_back(i);
      dc.push_back(j);

      int cost = 1;
      if (i == 1 && j == 0)
        cost = 0;
      if (i == -1 && j == 0)
        cost = 0;
      if (i == 0 && j == 1)
        cost = 0;
      if (i == 0 && j == -1)
        cost = 0;
      mv_to_cost[mv] = cost;
      mv++;
    }
  }

  int ans = bfs(R, C, sr - 1, sc - 1, gr - 1, gc - 1);

  cout << ans << endl;

  return 0;
}

Error: TLE

Fixed submission:


//

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// const int INF = 2147483647;
// const ll INF = 9223372036854775807;
// const ll MOD = 1e9 + 7;

const ll INF = 9223372036854775807;
const int UNCONF = 0;
const int CONF = 1;

struct Edge {
  int to;
  ll cost;
};

struct Node {
  vector<Edge> edges;
  int status;
  ll min_cost;
};

bool grid[1000][1000];
Node nodes[1000000];

// ダイクストラ法（優先度付きキューを使用）
// n: ノード数, start_idx: 開始ノードのインデックス
void Dijkstra(int n, int start_idx) {
  for (int i = 0; i < n; i++) {
    nodes[i].status = UNCONF;
    nodes[i].min_cost = INF;
  }

  nodes[start_idx].min_cost = 0;

  // PQ: <コスト,
  // ノード番号>のpairを格納する優先度付きキュー（コストが大きいもの優先）
  priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>>
      PQ;
  PQ.push(make_pair(0, start_idx));

  while (!PQ.empty()) {
    pair<ll, int> p = PQ.top();
    PQ.pop();
    ll cost = p.first;
    Node &node = nodes[p.second];

    if (cost > node.min_cost)
      continue; // 他にコストの低いルートが見つかったので使わない

    node.status = CONF;

    for (Edge edge : node.edges) {
      Node &next_node = nodes[edge.to];
      ll next_cost = (edge.cost == INF) ? INF : node.min_cost + edge.cost;
      if (next_node.status != CONF) {
        if (next_cost < next_node.min_cost) {
          next_node.min_cost = next_cost;
          PQ.push(make_pair(next_cost, edge.to));
        }
      }
    }
  }
}

int main() {
  int H, W, Ch, Cw, Dh, Dw;
  cin >> H >> W >> Ch >> Cw >> Dh >> Dw;

  Ch--;
  Cw--;
  Dh--;
  Dw--;

  map<pair<int, int>, int> pos_to_n;
  int n = 0;
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      char c;
      cin >> c;
      if (c == '#')
        grid[i][j] = true;
      pos_to_n[make_pair(i, j)] = n;
      n++;
    }
  }

  for (int h = 0; h < H; h++) {
    for (int w = 0; w < W; w++) {
      if (grid[h][w])
        continue;
      for (int i = -2; i <= 2; i++) {
        for (int j = -2; j <= 2; j++) {
          if (h + i < 0 || h + i >= H)
            continue;
          if (w + j < 0 || w + j >= W)
            continue;
          if (i == 0 && j == 0)
            continue;
          if (grid[h + i][w + j])
            continue;

          int cost = 1;
          if (i == -1 && j == 0)
            cost = 0;
          if (i == 1 && j == 0)
            cost = 0;
          if (i == 0 && j == -1)
            cost = 0;
          if (i == 0 && j == 1)
            cost = 0;

          // cout << h << "," << w << "->" << h+i << "," << w+j << endl;

          nodes[pos_to_n[make_pair(h, w)]].edges.push_back(
              Edge{pos_to_n[make_pair(h + i, w + j)], cost});
        }
      }
    }
  }

  // **** debug ****
  /*
  for (int i=0; i<n; i++) {
          cout << "node" << i;
          for (Edge e : nodes[i].edges) {
                  cout << " " << e.to << "(" << e.cost << ")";
          }
          cout << endl;
  }
  */

  Dijkstra(n, pos_to_n[make_pair(Ch, Cw)]);

  // **** debug ****
  /*
  for (int i=0; i<n; i++) {
          cout << "node" << i  << " " << nodes[i].min_cost << endl;
  }
  */

  // cout << pos_to_n[make_pair(Dh, Dw)] << endl;
  ll ans = nodes[pos_to_n[make_pair(Dh, Dw)]].min_cost;
  if (ans == INF)
    ans = -1;
  cout << ans << endl;

  return 0;
}