【图论】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优化
将普通队列换成双端队列,每次将入队结点距离和队首比较,如果更大则插入至队尾,否则插入队首。