Yuulis.log

トンネルを抜けるとそこは参照エラーであった。

【AtCoder】ABC 340 D - Super Takahashi Bros. | 茶コーダーが解くAtCoder

atcoder.jp


実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 784

問題概要

 1, 2, ..., N の番号が付いた  N 個のステージがあり、現在はステージ1のみが遊べる。各ステージ  i (1 \leq i \leq N - 1) が遊べるとき、ステージ  i では次の2つの行動のどちらかを行うことができる。各ステージをクリアするためにかかる時間以外は無視できるとき、ステージ  N を遊べるようになるのは最短で何秒後か。

  • 行動 :
  1.  A_i 秒かけてステージ  i をクリアする。結果、ステージ  i + 1 が遊べるようになる。
  2.  B_i 秒かけてステージ  i をクリアする。結果、ステージ  X_i が遊べるようになる。

制約

  • 入力はすべて整数。
  •  2 \leq N \leq 2 \times 10^5
  •  1 \leq A_i, B_i \leq 10^9
  •  1 \leq X_i \leq N

考察

頂点をステージ、辺の重みをステージが遊べるようになるまでの時間として、サンプルケース1の様子をグラフで図示してみると以下のようになる。太線矢印の遷移が最短となる。

サンプルケース1

一般化して考えると、求めたいのは頂点1から頂点  N までの最短経路ということになる。重み付き有向グラフにおいてある頂点からの最短経路を求めるときに使えるアルゴリズムは、「ダイクストラ (Dijkstra) 法」だ。

ダイクストラ法は、「ある1つの始点から各点への最短経路を求めるアルゴリズム」である。辺の重みが負になるものがある場合は使えないが、今回は時間が辺の重みになるため負の辺は存在しない。

ダイクストラ法を使えばよいということが分かれば実装自体はシンプルで、 1 から  N までの  N - 1 個の各頂点からそれぞれ2本の辺を張っていけばよい。

コード

#include <bits/stdc++.h>
using namespace std;

using ll = long long;

#define rep(i, start, end) for (ll i = (start); i < (ll)(end); i++)

// ======================================== //

struct Edge
{
    ll to;
    ll cost;
};

using Graph = vector<vector<Edge>>;
using Pair = pair<ll, ll>;

void Dijkstra(const Graph &graph, vector<ll> &distances, ll startIndex)
{
    priority_queue<Pair, vector<Pair>, greater<Pair>> p_queue;
    p_queue.emplace((distances[startIndex] = 0), startIndex);

    while (!p_queue.empty())
    {
        const ll distance = p_queue.top().first;
        const ll from = p_queue.top().second;
        p_queue.pop();

        if (distances[from] < distance)
            continue;

        for (const auto &edge : graph[from])
        {
            const ll new_distance = (distances[from] + edge.cost);

            if (new_distance < distances[edge.to])
                p_queue.emplace((distances[edge.to] = new_distance), edge.to);
        }
    }
}

int main()
{
    int N;
    cin >> N;

    Graph G(200020);
    rep(i, 1, N)
    {
        ll A, B, X;
        cin >> A >> B >> X;
        G[i].push_back(Edge{i + 1, A});
        G[i].push_back(Edge{X, B});
    }

    vector<ll> dist(N + 1, INFL);
    Dijkstra(G, dist, 1);

    cout << dist[N] << endl;
}

atcoder.jp

実装時間: 40分

最初に動的計画法で実装してしまい、サンプルケース2で落とされてしまった。時系列順の探索はダイクストラ法という認識で良いのかもしれない。