Yuulis.log

Yuulis.log

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

【AtCoder】ABC 362 D - Shortest Path 3 | 茶コーダーが解くAtCoder

atcoder.jp

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

問題概要

 N 頂点  M 辺の単純連結無向グラフが与えられる。頂点  i A_i の重みを持ち、辺  j は頂点  U_j, V_j に接続しており重み  B_j を持つ。このとき、各  i : (i = 2, 3, \cdots, N) について、頂点  1 から 頂点  i までのパスであって、パス上に現れる頂点の重みと辺の重みの総和が最小となるものの値を求めよ。

制約

  • 入力はすべて整数。
  •  2 \leq N \leq 2 \times 10^5
  •  N-1 \leq M \leq 2 \times 10^5
  •  1 \leq U_j \lt V_j \leq N
  •  0 \leq A_i, B_j \leq 10^9

考察

頂点  1 を始点とする単一始点最短路問題ということで、このような問題は Dijkstra 法を用いて解を得ることができる。


一つ注意したいのは、本問では辺だけではなく頂点にも重みが付加されているということだ。一般的な Dijkstra 法のアルゴリズムでは辺にしか重みを付加できない。

そこで、辺の重みに頂点の重みを足し合わせてしまおう。具体的には、頂点  u, v を結ぶ辺  e について、  u \to v 方向については重みを  B_e + A_v v \to u 方向については重みを  B_e + A_u とする。

このようなグラフ上で Dijkstra 法を適用し、最後に  A_1 の重みを加えることで答えを求められる。

コード

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

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

constexpr auto INFL = 1LL << 60;

using ll = long long;
template <class T>
using Graph = vector<vector<T>>;


template <typename T>
inline bool chmin(T &a, T b) { return ((a > b) ? (a = b, true) : (false)); }

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

using Pair_edge = std::pair<long long, int>;

struct Edge
{
    int to;
    long long cost;
};

// Solve the shortest path problem from the start point in the graph.
void Dijkstra(const Graph<Edge> &graph, std::vector<long long> &dist, const int start)
{
    std::priority_queue<Pair_edge, std::vector<Pair_edge>, std::greater<Pair_edge>> que;
    que.emplace((dist[start] = 0), start);

    while (!que.empty())
    {
        const long long distance = que.top().first;
        const int from = que.top().second;
        que.pop();

        if (dist[from] < distance)
            continue;

        for (const auto &edge : graph[from])
        {
            if (chmin(dist[edge.to], dist[from] + edge.cost))
            {
                que.emplace(dist[edge.to], edge.to);
            }
        }
    }
}

int main()
{
    int N, M;
    cin >> N >> M;
    vector<ll> A(N);
    rep(i, 0, N) cin >> A[i];
    Graph<Edge> G(N);
    rep(i, 0, M)
    {
        int U, V;
        cin >> U >> V;
        ll B;
        cin >> B;
        G[U - 1].push_back({V - 1, B + A[V - 1]});
        G[V - 1].push_back({U - 1, B + A[U - 1]});
    }

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

    rep(i, 1, N)
    {
        cout << A[0] + dist[i] << " ";
    }
    cout << endl;
}

atcoder.jp

実装時間: 20分


Dijkstra 法の実装に一工夫加えるという、とても教育的な問題だと思う。