Bellman-Ford
描述
可以应用于有负环的情况。
在含负环的情况中, 如果最短路存在,那么一定存在不含环的最短路,这样最短路最多经过n-1个结点, 因此进行n-1次循环, 每次循环检查所有的边d[u][v] ,进行松弛操作。n-1次松弛操作完成后, 寻找是不是存在d[y] < d[x] + w[i], 如果存在, 说明有负环->最短路不存在
代码
for(int i=0; i<n; i++)
d[i] = INF;
d[0] = 0;
for(int i=0; i<n-1; i++)
{
for(int j=0; i<m ; j++)
{
int x = u[i], y = v[i];
if(d[x] < INF)
d[y] = min(d[y], d[x] + w[x][y]);
}
}
bool flag = 1;
for(int i=0; i<n; i++)
{
int x = u[i], y = v[i];
if(d[y] > d[x]+w[x][y])
{
flag = 0;
break;
}
}
SPFA
描述
就是Bellman-Ford算法的队列优化,用先进先出的队列代替循环检查,减少本来就不能更新的结点的重新检查,提高效率:
维护一个队列,将源点放入队列,对与它相邻的点进行松弛, 将松弛成功的点放入队列,直到队列为空时算法结束。
struct Edge
{
int from; to; dist;
Edge(int u, int v, int d):from(u), to(v), dist(d){}
};
bool SPFA(int s)
{
queue<int> Q;
memset(inq, 0, sizeof(inq));
memset(cnt, 0, sizeof(cnt));
for(int i=0; i<n; i++)
{
d[i] = INF;
}
d[s] = 0;
inq[s] = 1;
Q.push(s);
while(!q.empty)
{
int u = Q.front();
Q.pop();
inq[u] = 0;
for(int i=0; i<G[u].size(); i++)
{
Edge& e = edges[G[u][i]];
if(d[u] = INF && d[e.to] > d[u] + e.dist)
{
d[e.to] = d[u] + e.dist;
p[e.to] = G[u][i];
if(!inq[e.to])
{
Q.push(e.to);
inq[e.to] = 1;
if(++cnt[e.to] > n)
return 0;
}
}
}
}
return 1;
}