ダイクストラ法 aoj 単一頂点最短距離

ALDS1_12_C 単一頂点最短距離 2

ALDS1_12_C 単一頂点最短距離 2
Feb. 2, 2020, 1:52 p.m.

目次

問題

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_12_C

解説

隣接リストと優先度付きキューによるダイクストラ法

重み付き有向グラフのある頂点から各頂点への最短距離をもとめる.

各頂点は頂点<重み, ID>というペアで表す.

priority_queueのデフォルトの設定のままで重み順にソートさせるために、2つの工夫をしている.

  1. IDではなく重みをペアの第一要素にしている.
  2. デフォルトでは重みの大きい順にソートされてしまうので(最大ヒープ)、プッシュする際に重みに-1をかけて、ポップする時にもう一度-1をかけてもとに戻すことで最小ヒープにしている.

こうしないと、priority_queue に独自の比較オブジェクトを用意する必要がある.

グラフは、頂点数が多いので隣接行列ではなく隣接リストで表現する.


    1. 2つのコンテナと1つの優先度付きキューを宣言する



      1. done[n] 各頂点の最短距離が確定したかいなか





      1. dist[n] 各頂点の今考えれる最短距離(実行完了までは確定とは限らない)





      1. priority_queue<Node> PQ 未確定でかつ原点からの距離が短い頂点順に並んだキュー




    1. コンテナを初期化する



      1. done 全頂点false





      1. dist 原点自身0は距離0を、その他は∞





      1. PQ 原点0を距離0でプッシュする




    1. キューが空になるまで以下を繰り返す



      1. キューの先頭uを取得し、未確定であれば次に進む





      1. 確定済みにする





      1. すべての隣接頂点vについて以下を実行する





      1. vが未確定であれば次に進む





      1. 原点からuまでのコストdist[u]とuからvへ距離weight(v)の和が今の所考えられていた原点からvまでの最小距離dist[v]よりも小さければ





        1. 最小距離を更新する








        1. キューにvのIDと原点からの最小距離をペアにしてプッシュする(この時距離をマイナスにするのを忘れずに)







    1. distに原点0から各頂点への最短距離が確定されている

解答

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#define MAX_N 10000
#define W_INF (1 << 21)


typedef pair<Int, Int> Node;

#define make_node(v,c) (make_pair(v,c))
#define weight(n) (n.first)
#define vertex(n) (n.second)


void sssp(vector<Node> nodes[], Int n, Int dist[]) {
  bool done[n];
  priority_queue<Node> PQ;

  loop(i,0,n) done[i] = false, dist[i] = W_INF;
  dist[0] = 0, PQ.push(make_node(0, 0));

  while (!PQ.empty()) {
    Node node = PQ.top(); PQ.pop();
    Int u = vertex(node);
    if (done[u]) continue;
    done[u] = true;

    for (auto n_v: nodes[u]) {
      Int v = vertex(n_v);
      if (done[v]) continue;
      Int w = weight(n_v);

      if (dist[u] + w < dist[v]) {
        dist[v] = dist[u] + w;
        PQ.push(make_node(dist[v] * (-1), v));
      }
    }
  }
}


int main(void) {
  Int n, k, v, c;
  cin >> n;
  vector<Node> nodes[n];
  Int dist[n];

  loop(u,0,n) {
    cin >> k >> k;
    loop(i,0,k) {
      cin >> v >> c;
      nodes[u].push_back(make_node(c, v));
    }
  }

  sssp(nodes, n, dist);
  loop(i,0,n) cout << i << " " << dist[i] << endl;
}