Home > libalgo > 両側ダイクストラによる二点間最短路 (有向グラフ対応)

両側ダイクストラによる二点間最短路 (有向グラフ対応)

2019/08/12: 有向グラフ対応

概要

無向グラフの $s$-$t$ 最短路を,両側からダイクストラすることで求める. $\mu = \min_{e = vw \in E}$ { s-v 最短距離 + $e$ の重み + w-t 最短距離} が,2 つのヒープの先頭の和以上になったら $\mu$ を返す. 辺の向きを逆にしたグラフを使うと有向グラフに対応できる.

使い方

グラフ g,始点 s,終点 t, 有向グラフであるかのフラグ dir を渡すと s-t 最短距離を返す (dir <=> g が有向グラフ). 負辺はダメ.

計算量

$O((V+E) \log V)$

実装

Graph makeReversed(const Graph &g) {
    int n = g.size();
    Graph revg(n);
    for (auto &es : g) {
        for (auto &e: es) {
            Edge re = e;
            std::swap(re.src, re.dst);
            revg[re.src].push_back(re);
        }
    }
    return revg;
}

Weight bidirectionalDijkstraImpl(const Graph &g, const Graph &rg, int s, int t) {
    int n = g.size();

    using State = std::pair<Weight, int>;
    std::priority_queue<State, std::vector<State>, std::greater<State>> pq[2];
    pq[0].emplace(0, s);
    pq[1].emplace(0, t);

    constexpr Weight INF = std::numeric_limits<Weight>::max() / 8;
    std::vector<Weight> dist[2];
    dist[0] = dist[1] = std::vector<Weight>(n, INF);
    dist[0][s] = dist[1][t] = 0;

    const Graph *gs[2] = { &g, &rg };

    Weight mu = INF;
    while (pq[0].size() && pq[1].size()) {
        if (pq[0].top().first + pq[1].top().first >= mu) break;
        int k = pq[0].top().first <= pq[1].top().first ? 0 : 1;
        Weight d;
        int v;
        std::tie(d, v) = pq[k].top();
        pq[k].pop();
        if (d < dist[k][v]) continue;
        for (auto &e : (*gs[k])[v]) {
            Weight w = e.dst;
            if (dist[k][w] > dist[k][v] + e.weight) {
                dist[k][w] = dist[k][v] + e.weight;
                pq[k].emplace(dist[k][w], w);
                mu = std::min(mu, dist[k][v] + e.weight + dist[1 - k][w]);
            }
        }
    }
    return mu;
    
}

Weight bidirectionalDijkstra(const Graph &g, int s, int t, bool dir) {
    if (s == t) return 0;
    if (dir) {
        Graph revg = makeReversed(g);
        return bidirectionalDijkstraImpl(g, revg, s, t);
    } else {
        return bidirectionalDijkstraImpl(g, g, s, t);
    }
}

検証

想定解法ではないので一部 TLE だが多くで AC

参考文献

http://tatanaideyo.hatenablog.com/entry/2015/11/01/031713