atcoder.jp
実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 784
考察
頂点をステージ、辺の重みをステージが遊べるようになるまでの時間として、サンプルケース1の様子をグラフで図示してみると以下のようになる。太線矢印の遷移が最短となる。
一般化して考えると、求めたいのは頂点1から頂点 までの最短経路ということになる。重み付き有向グラフにおいてある頂点からの最短経路を求めるときに使えるアルゴリズムは、「ダイクストラ (Dijkstra) 法」だ。
ダイクストラ法は、「ある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で落とされてしまった。時系列順の探索はダイクストラ法という認識で良いのかもしれない。