【AtCoder】ABC 481 D - Autopilot

D - Autopilotatcoder.jp favicon

実行時間制限: 2 sec / メモリ制限: 1024 MiB / Difficulty: 581 / NoviSteps: 2Q / 配点: 400 点

問題概要

NN 個の惑星と MM 本の航路があり、航路 ii は惑星 AiA_i から惑星 BiB_i へと結ばれていて、各航路は一方通行である。

この空間において、宇宙船は以下の 22 種類の操作を行うことができる。

  • 今いる惑星から航路が直接結ばれた惑星のうち、番号が最小の惑星に、燃料を消費せずに移動する。
  • 今いる惑星から航路が直接結ばれた惑星を好きに選び、燃料を 11 消費して選んだ惑星に移動する。

宇宙船が惑星 SS から出発して惑星 TT に到着するまでに消費する燃料の量の最小値を求めよ。 到達が不可能な場合は代わりに −1-1 を出力すること。

制約

  • 2≤N≤2×1052 \leq N \leq 2 \times 10^5
  • 1≤M≤2×1051 \leq M \leq 2 \times 10^5
  • 1≤S,T≤N1 \leq S,T \leq N
  • S≠TS \neq T
  • 1≤Ai,Bi≤N1 \leq A_i, B_i \leq N
  • Ai≠BiA_i \neq B_i
  • 入力される値はすべて整数

考察

まず、各有向辺に対してコスト 00 または 11 を設定する。 ただし、コスト 00 の辺は、各惑星から出る航路のうち、行き先の惑星番号が最小となる辺だけである。

具体的には、惑星 uu から惑星 vv への航路に対し、コスト c(u,v)c(u,v) を次のように定義する。

c(u,v)={0(v=min⁡{Bi∣Ai=u})1(else)c(u,v)= \begin{cases} 0 & (v=\min\{B_i\mid A_i=u\})\\ 1 & (\text{else}) \end{cases}

これにより、求める答えは SS から TT への最短距離になる。


これは、01-BFS で解くのが簡単だろう。

通常の BFS と違って、dequeを使うことで、コスト 00 の辺を通る場合は先頭に追加し、コスト 11 の辺を通る場合は末尾に追加することで、効率的に最短距離を求めることができる。

計算量は、O(N+M)O(N + M) である。

実装例

CPP
1.#include <bits/stdc++.h>
2.using namespace std;
3.
4.#define rep(i, start, end) for (auto i = (start); (i) < (end); (i)++)
5.
6.constexpr int INF = 1e+9;
7.
8.template <class T>
9.using Graph = vector<vector<T>>;
10.
11.template <typename T>
12.inline bool chmin(T& a, T b) { return ((a > b) ? (a = b, true) : (false)); }
13.
14.// ======================================== //
15.
16.int main()
17.{
18. int N, M, S, T;
19. cin >> N >> M >> S >> T;
20. Graph<int> G(N);
21. vector<int> min_v(N, INF);
22. rep(i, 0, M) {
23. int A, B;
24. cin >> A >> B;
25. A--;
26. B--;
27. G[A].push_back(B);
28. chmin(min_v[A], B);
29. }
30.
31. vector<int> dist(N, INF);
32. deque<int> que;
33. dist[S - 1] = 0;
34. que.push_back(S - 1);
35. while (!que.empty()) {
36. int now = que.front();
37. que.pop_front();
38.
39. for (auto next : G[now]) {
40. int cost = (next == min_v[now] ? 0 : 1);
41.
42. if (dist[next] > dist[now] + cost) {
43. dist[next] = dist[now] + cost;
44.
45. if (cost == 0) {
46. que.push_front(next);
47. }
48. else {
49. que.push_back(next);
50. }
51. }
52. }
53. }
54.
55. if (dist[T - 1] == INF) {
56. cout << -1 << endl;
57. }
58. else {
59. cout << dist[T - 1] << endl;
60. }
61.
62. return 0;
63.}
atcoder.jp favicon

実装時間: 10分

コメント

Dijkstra法より 01-BFS の方が、若干計算量が改善されていいね。