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

#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdio.h>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
typedef long long ll;
const double EPS = 1e-9;
typedef vector<int> vint;
typedef vector<vector<int>> v2int;
typedef vector<vector<vector<int>>> v3int;
typedef vector<ll> vll;
typedef vector<vector<ll>> v2ll;
typedef vector<vector<vector<ll>>> v3ll;
typedef list<int> liint;
typedef pair<int, int> pint;
typedef vector<pair<int, int>> vpint;
typedef vector<pair<ll, ll>> vpll;
typedef vector<pair<ll, int>> vpll_int;
typedef vector<pair<int, ll>> vpint_ll;
typedef set<pair<int, int>> spint;
typedef set<pair<ll, int>> spll;
typedef unordered_map<int, unordered_set<int>> Graph;
const int INF = int(2e9);
const ll LINF = ll(2e9) * ll(2e9);
#define rep(i, n) REP(i, 0, n)
#define ALL(v) v.begin(), v.end()
#define MSG(a) cout << #a << " " << a << endl;
#define REP(i, x, n) for (int i = x; i < n; i++)
template <class T, class C> void chmax(T &a, C b) { a > b ?: a = b; }
template <class T, class C> void chmin(T &a, C b) { a < b ?: a = b; }

class edge {
public:
  edge(int to, long long cost);
  int get_to() const;
  long long get_cost() const;

private:
  int to;
  long long cost;
};

edge::edge(int to, long long cost) : to(to), cost(cost) {}

int edge::get_to() const { return to; }

long long edge::get_cost() const { return cost; }

class dykstra {
private:
  // unordered_mapを使って隣接を構築
  // first:接続元、second:辺のコストと接続先
  std::unordered_map<int, std::vector<edge>> adj_list;
  int node_num;
  int start_point;
  std::vector<long long> costs; // 距離を保持
  std::vector<bool> is_done;    // 確定ノードか否かを保持

public:
  dykstra(const int node_num,
          const std::unordered_map<int, std::vector<edge>> &adj_list);
  void calc_min_cost(int start);
  long long get_cost(int end) const;
};

dykstra::dykstra(const int node_num,
                 const std::unordered_map<int, std::vector<edge>> &adj_list)
    : adj_list(adj_list), start_point(0), node_num(node_num),
      costs(node_num + 1, LINF), is_done(node_num + 1, false) {}

void dykstra::calc_min_cost(int start) {
  this->start_point = start;
  this->costs = std::vector<long long>(node_num + 1, LINF);
  this->is_done = std::vector<bool>(node_num + 1, false);

  // 優先度付きキューpairで頂点番号と最短距離を保持
  // firstの要素で比較されるので、firstが距離、secondを頂点番号とする
  std::priority_queue<std::pair<long long, int>,
                      std::vector<std::pair<long long, int>>,
                      std::greater<std::pair<long long, int>>>
      p_queue;
  p_queue.push(std::make_pair(0, start));
  costs[start] = 0;
  while (1) {
    if (p_queue.empty() == true)
      break; // キューが空なら終了
    std::pair<long long, int> cost_node = p_queue.top();
    p_queue.pop();
    is_done[cost_node.second] = true; // キューから取り出した頂点を確定頂点とする
    for (auto &it : adj_list[cost_node.second]) {
      int adj_node = it.get_to();
      if (is_done[adj_node] == false) {
        long long adj_cost = it.get_cost() + cost_node.first;
        if (adj_cost <
            costs
                [adj_node]) { // 計算された隣接頂点のコストが現在のコストより小さいなら
          costs[adj_node] = adj_cost; // 隣接頂点のコストを更新
          p_queue.push(std::make_pair(
              adj_cost, adj_node)); // キューに隣接頂点の情報を突っ込む
        }
      }
    }
  }
}

long long dykstra::get_cost(int end) const { return costs[end]; }

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  int H, W;
  cin >> H >> W;
  int Ch, Cw;
  cin >> Ch >> Cw;
  int Dh, Dw;
  cin >> Dh >> Dw;
  unordered_map<int, pair<int, int>> nd2cord;
  // map<pair<int, int>, int> cord2nd;
  v2int cord2nd(H, vint(W));
  vector<vector<char>> field(H, vector<char>(W));
  int nd = 0;
  rep(i, H) {
    rep(j, W) {
      cin >> field[i][j];
      cord2nd[i][j] = nd;
      nd++;
    }
  }
  vector<pair<int, int>> move = {make_pair(0, 1), make_pair(0, -1),
                                 make_pair(-1, 0), make_pair(1, 0)};
  std::unordered_map<int, std::vector<edge>> graph;
  rep(i, H) {
    rep(j, W) {
      for (auto &m : move) {
        int new_i = i + m.first;
        int new_j = j + m.second;
        if (new_i < 0)
          continue;
        if (new_j < 0)
          continue;
        if (new_i >= H)
          continue;
        if (new_j >= W)
          continue;
        if (field[new_i][new_j] == '#')
          continue;
        int now_nd = cord2nd[i][j];
        int adj_nd = cord2nd[new_i][new_j];
        graph[now_nd].push_back(edge(adj_nd, 0));
      }

      for (int ri = -2; ri <= 2; ri++) {
        for (int rj = -2; rj <= 2; rj++) {
          if (ri == 0 && rj == 0)
            continue;
          int new_i = i + ri;
          int new_j = j + rj;
          if (new_i < 0)
            continue;
          if (new_j < 0)
            continue;
          if (ri == 1 && rj == 0)
            continue;
          if (ri == -1 && rj == 0)
            continue;
          if (ri == 0 && rj == 1)
            continue;
          if (ri == 0 && rj == -1)
            continue;
          if (new_i >= H)
            continue;
          if (new_j >= W)
            continue;
          if (field[new_i][new_j] == '#')
            continue;
          int now_nd = cord2nd[i][j];
          int adj_nd = cord2nd[new_i][new_j];

          graph[now_nd].push_back(edge(adj_nd, 1));
        }
      }
    }
  }

  dykstra d(H * W, graph);
  d.calc_min_cost(cord2nd[Ch - 1][Cw - 1]);
  ll ans = d.get_cost(cord2nd[Dh - 1][Dw - 1]);
  if (ans == LINF) {
    cout << -1 << endl;
  } else {
    cout << ans << endl;
  }
  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdio.h>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
typedef long long ll;
const double EPS = 1e-9;
typedef vector<int> vint;
typedef vector<vector<int>> v2int;
typedef vector<vector<vector<int>>> v3int;
typedef vector<ll> vll;
typedef vector<vector<ll>> v2ll;
typedef vector<vector<vector<ll>>> v3ll;
typedef list<int> liint;
typedef pair<int, int> pint;
typedef vector<pair<int, int>> vpint;
typedef vector<pair<ll, ll>> vpll;
typedef vector<pair<ll, int>> vpll_int;
typedef vector<pair<int, ll>> vpint_ll;
typedef set<pair<int, int>> spint;
typedef set<pair<ll, int>> spll;
typedef unordered_map<int, unordered_set<int>> Graph;
const int INF = int(2e9);
const ll LINF = ll(2e9) * ll(2e9);
#define rep(i, n) REP(i, 0, n)
#define ALL(v) v.begin(), v.end()
#define MSG(a) cout << #a << " " << a << endl;
#define REP(i, x, n) for (int i = x; i < n; i++)
template <class T, class C> void chmax(T &a, C b) { a > b ?: a = b; }
template <class T, class C> void chmin(T &a, C b) { a < b ?: a = b; }

class edge {
public:
  edge(int to, long long cost);
  int get_to() const;
  long long get_cost() const;

private:
  int to;
  long long cost;
};

edge::edge(int to, long long cost) : to(to), cost(cost) {}

int edge::get_to() const { return to; }

long long edge::get_cost() const { return cost; }

class dykstra {
private:
  // unordered_mapを使って隣接を構築
  // first:接続元、second:辺のコストと接続先
  std::unordered_map<int, std::vector<edge>> adj_list;
  int node_num;
  int start_point;
  std::vector<long long> costs; // 距離を保持
  std::vector<bool> is_done;    // 確定ノードか否かを保持

public:
  dykstra(const int node_num,
          const std::unordered_map<int, std::vector<edge>> &adj_list);
  void calc_min_cost(int start);
  long long get_cost(int end) const;
};

dykstra::dykstra(const int node_num,
                 const std::unordered_map<int, std::vector<edge>> &adj_list)
    : adj_list(adj_list), start_point(0), node_num(node_num),
      costs(node_num + 1, LINF), is_done(node_num + 1, false) {}

void dykstra::calc_min_cost(int start) {
  this->start_point = start;
  this->costs = std::vector<long long>(node_num + 1, LINF);
  this->is_done = std::vector<bool>(node_num + 1, false);

  // 優先度付きキューpairで頂点番号と最短距離を保持
  // firstの要素で比較されるので、firstが距離、secondを頂点番号とする
  std::priority_queue<std::pair<long long, int>,
                      std::vector<std::pair<long long, int>>,
                      std::greater<std::pair<long long, int>>>
      p_queue;
  p_queue.push(std::make_pair(0, start));
  costs[start] = 0;
  while (1) {
    if (p_queue.empty() == true)
      break; // キューが空なら終了
    std::pair<long long, int> cost_node = p_queue.top();
    p_queue.pop();
    is_done[cost_node.second] = true; // キューから取り出した頂点を確定頂点とする
    for (auto &it : adj_list[cost_node.second]) {
      int adj_node = it.get_to();
      if (is_done[adj_node] == false) {
        long long adj_cost = it.get_cost() + cost_node.first;
        if (adj_cost <
            costs
                [adj_node]) { // 計算された隣接頂点のコストが現在のコストより小さいなら
          costs[adj_node] = adj_cost; // 隣接頂点のコストを更新
          p_queue.push(std::make_pair(
              adj_cost, adj_node)); // キューに隣接頂点の情報を突っ込む
        }
      }
    }
  }
}

long long dykstra::get_cost(int end) const { return costs[end]; }

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  int H, W;
  cin >> H >> W;
  int Ch, Cw;
  cin >> Ch >> Cw;
  int Dh, Dw;
  cin >> Dh >> Dw;
  unordered_map<int, pair<int, int>> nd2cord;
  map<pair<int, int>, int> cord2nd;

  vector<vector<char>> field(H, vector<char>(W));
  int nd = 0;
  rep(i, H) {
    rep(j, W) {
      cin >> field[i][j];
      cord2nd[make_pair(i, j)] = nd;
      nd++;
    }
  }
  vector<pair<int, int>> move = {make_pair(0, 1), make_pair(0, -1),
                                 make_pair(-1, 0), make_pair(1, 0)};
  std::unordered_map<int, std::vector<edge>> graph;
  rep(i, H) {
    rep(j, W) {
      for (auto &m : move) {
        int new_i = i + m.first;
        int new_j = j + m.second;
        if (new_i < 0)
          continue;
        if (new_j < 0)
          continue;
        if (new_i >= H)
          continue;
        if (new_j >= W)
          continue;
        if (field[new_i][new_j] == '#')
          continue;
        int now_nd = cord2nd[make_pair(i, j)];
        int adj_nd = cord2nd[make_pair(new_i, new_j)];
        graph[now_nd].push_back(edge(adj_nd, 0));
      }

      for (int ri = -2; ri <= 2; ri++) {
        for (int rj = -2; rj <= 2; rj++) {
          if (ri == 0 && rj == 0)
            continue;
          int new_i = i + ri;
          int new_j = j + rj;
          if (new_i < 0)
            continue;
          if (new_j < 0)
            continue;
          if (ri == 1 && rj == 0)
            continue;
          if (ri == -1 && rj == 0)
            continue;
          if (ri == 0 && rj == 1)
            continue;
          if (ri == 0 && rj == -1)
            continue;
          if (new_i >= H)
            continue;
          if (new_j >= W)
            continue;
          if (field[new_i][new_j] == '#')
            continue;
          int now_nd = cord2nd[make_pair(i, j)];
          int adj_nd = cord2nd[make_pair(new_i, new_j)];

          graph[now_nd].push_back(edge(adj_nd, 1));
        }
      }
    }
  }

  dykstra d(H * W, graph);
  d.calc_min_cost(cord2nd[make_pair(Ch - 1, Cw - 1)]);
  ll ans = d.get_cost(cord2nd[make_pair(Dh - 1, Dw - 1)]);
  if (ans == LINF) {
    cout << -1 << endl;
  } else {
    cout << ans << endl;
  }
  return 0;
}