全局最短路(Global Shortest Path)

普通的 Floyd、Floyd 传递闭包、Johnson 算法。

Floyd

#include <cstdio>
#include <climits>
#include <algorithm>

const int MAXN = 1005;

int dist[MAXN][MAXN];

void floyd(int n) {
    for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) if (dist[i][k] < INT_MAX)
        for (int j = 1; j <= n; j++) if (dist[k][j] < INT_MAX)
            dist[i][j] = std::min(dist[i][j], dist[i][k] + dist[k][j]);
}

int main() {
    int n, m;
    scanf("%d %d", &n, &m);

    for (int i = 1; i <= n; i++) std::fill(dist[i] + 1, dist[i] + n + 1, INT_MAX);

    for (int i = 0, u, v, w; i < m; i++) {
        scanf("%d %d %d", &u, &v, &w);
        dist[u][v] = dist[v][u] = std::min(dist[u][v], w);
    }

    floyd(n);
    // dist[i][i] is the length of minimum circle through i if it's a digraph

    return 0;
}

Floyd 传递闭包

#include <cstdio>
#include <bitset>
#include <algorithm>

const int MAXN = 2005;

std::bitset<MAXN> G[MAXN];

void floyd(int n) {
    for (int k = 0; k < n; k++) for (int i = 0; i < n; i++)
        if (G[i][k]) G[i] |= G[k];
}

int main() {
    int n, m;
    scanf("%d %d", &n, &m);

    for (int i = 0, u, v; i < m; i++) {
        scanf("%d %d", &u, &v);
        G[u].set(v);
    }
    for (int i = 0; i < n; i++) G[i].set(i);

    floyd(n);

    return 0;
}

Johnson

用于求稀疏(有向)图的全局最短路。如果边权均非负,可省略第一步的 Bellman-Ford。

#include <cstdio>
#include <climits>
#include <queue>
#include <algorithm>

const int MAXN = 2005;
const int MAXM = 10005;

struct Edge;
struct Node {
    Edge *e;
    int dist[MAXN], cnt, h; // N[j].dist[i] denotes the shortest path from i to j
    bool inq, vis;
} N[MAXN];

struct Edge {
    Node *u, *v;
    Edge *next;
    int w;

    Edge() {}
    Edge(Node *u, Node *v, int w) : u(u), v(v), w(w), next(u->e) {}
} _pool[MAXM + MAXN], *_curr = _pool;

void addEdge(int u, int v, int w) {
    N[u].e = new (_curr++) Edge(&N[u], &N[v], w);
}

namespace BellmanFord {
    bool bellmanFord(Node *s, int n) {
        std::queue<Node *> q;
        q.push(s);
        s->h = 0;

        while (!q.empty()) {
            Node *u = q.front();
            q.pop();
            u->inq = false;

            for (Edge *e = u->e; e; e = e->next) {
                if (e->v->h > u->h + e->w) {
                    e->v->h = u->h + e->w;

                    if (++e->v->cnt >= n) return false;
                    if (!e->v->inq) {
                        e->v->inq = true;
                        q.push(e->v);
                    }
                }
            }
        }
        return true;
    }

    void solve(int s, int n) {
        for (int i = 0; i < n; i++) {
            N[i].h = INT_MAX;
            N[i].cnt = 0;
            N[i].inq = false;
        }

        bellmanFord(&N[s], n);
    }
} // namespace BellmanFord

namespace Dijkstra {
    struct HeapNode {
        Node *u;
        int dist;

        HeapNode(int dist, Node *u) : u(u), dist(dist) {}

        bool operator<(const HeapNode &rhs) const {
            return dist > rhs.dist;
        }
    };

    void dijkstra(Node *s, int id) {
        std::priority_queue<HeapNode> q;
        s->dist[id] = 0;
        q.emplace(0, s);

        while (!q.empty()) {
            Node *u = q.top().u;
            q.pop();

            if (u->vis) continue;
            u->vis = true;

            for (Edge *e = u->e; e; e = e->next) {
                if (e->v->dist[id] > u->dist[id] + e->w) {
                    e->v->dist[id] = u->dist[id] + e->w;

                    q.emplace(e->v->dist[id], e->v);
                }
            }
        }
    }

    void solve(int s, int n) {
        for (int i = 1; i <= n; i++) {
            N[i].dist[s] = INT_MAX;
            N[i].vis = false;
        }

        dijkstra(&N[s], s);
    }
} // namespace Dijkstra

int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    for (int i = 0, u, v, w; i < m; i++) {
        scanf("%d %d %d", &u, &v, &w);
        addEdge(u, v, w);
    }

    for (int i = 1; i <= n; i++) addEdge(0, i, 0);
    BellmanFord::solve(0, n + 1);
    for (Edge *e = _pool; e < _curr - n; e++) e->w += e->u->h - e->v->h;
    for (int i = 1; i <= n; i++) {
        Dijkstra::solve(i, n);
        for (int j = 1; j <= n; j++) N[j].dist[i] -= N[i].h - N[j].h;
    }

    return 0;
}

results matching ""

    No results matching ""