当负权值存在时,最短路不一定存在,但还是有办法在最短路存在的情况下求出来的。
在介绍之前,需要确定一件事:
如果最短路存在,则一定存在一个不含环的最短路。
理由:
在边权可正可负的图中,环游零环、正环、负环3种。如果包含零环或正环,去掉以后路径不会变长;如果包含负环,则意味着最短路不存在。
既然没有环,最短路最多只经过不含起点在内的n-1个节点,可以通过n-1“轮”松弛操作得到。像如下代码:
for(int i=0; i<n; i++)
{
d[i]=INF;
}
d[0]=0;
for(int k=0; k<n-1; k++)//迭代n-1次
{
for(int i=0; i<m; i++)//检查每条边
{
int x=u[i],y=v[i];
if(d[x]<INF)
{
d[y]=min(d[y],d[x]+w[i]);//松弛操作
}
}
}
上述算法就是Bellman-Ford算法。我们也可以用FIFO队列来代替上面的循环检查。像如下代码:
bool bellman_ford(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]=true;
Q.push(s);
while(!Q.empty())
{
int u=Q.front();
Q.pop();
inq[i]=false;
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.tp]=G[u][i];
if(!inq[e.to])
{
Q.push(e.to);
inqle[e.to]=true;
if(++cnt[e.to]>n)
{
return false;
}
}
}
}
}
}
时间复杂度:O(nm)。
参考文献:紫书
以上就是本文的全部内容啦!感谢阅读!