【图论】BellmanFord算法

适用于任何权的图,负权也可以做。假如从s出发的子图中存在负环,则算法会报告发现负环,否则会正确求出最短路。

松弛操作

一种基于松弛(relax)操作的最短路算法。

第i轮松弛(每条边使用一次)后,从节点s出发的经过<=i条边的到达每个节点的最短路已经找到。假如存在最短路,则最多经过n-1条边。所以假如一条边被松弛了n次,则不存在(从s到达v的)最短路。

BellmanFord算法

队列优化

成功入队的才是相比上一轮松弛有变化的点,其他的点不需要松弛。

返回值表示是否不存在从s出发能到达的负环。

namespace BellmanFord {

    const int MAXN = 2e5 + 10;

    int n;
    vector<pii> G[MAXN];

    ll dis[MAXN];
    int cnt[MAXN];
    bool vis[MAXN];

    queue<int> Q;

    bool bellmanford(int s) {
        fill(dis + 1, dis + 1 + n, LINF);
        fill(cnt + 1, cnt + 1 + n, 0);
        fill(vis + 1, vis + 1 + n, 0);
        while(!Q.empty())
            Q.pop();
        dis[s] = 0;
        vis[s] = 1;
        Q.push(s);
        while(!Q.empty()) {
            int u = Q.front();
            Q.pop();
            vis[u] = 0;
            ++cnt[u];
            if(cnt[u] == n)
                return false;
            for(pii &p : G[u]) {
                int v = p.first;
                int w = p.second;
                if(dis[v] <= dis[u] + w)
                    continue;
                dis[v] = dis[u] + w;
                if(!vis[v]) {
                    vis[v] = 1;
                    Q.push(v);
                }
            }
        }
        return true;
    }

}

乱优化

除了队列优化以外,其他的奇奇怪怪的优化完全不知道其道理何在。

栈优化

这个也是改变了点松弛的顺序,不再满足每一轮松弛原本的定义,所以n轮松弛不一定够(即超过n次松弛仍然可能不是负环),最差复杂度为指数级。

优先队列优化

这个也是改变了点松弛的顺序,不再满足每一轮松弛原本的定义,所以n轮松弛不一定够(即超过n次松弛仍然可能不是负环),最差复杂度为指数级。

LLL优化

将普通队列换成双端队列,每次将入队结点距离和队内距离平均值比较,如果更大则插入至队尾,否则插入队首。

SLF优化

将普通队列换成双端队列,每次将入队结点距离和队首比较,如果更大则插入至队尾,否则插入队首。

原文地址:https://www.cnblogs.com/purinliang/p/14388016.html