1.bellman-ford算法
能够处理存在负边权的情况。
算法时间复杂度:(NM),N是顶点数,M是边数。
算法实现:
设s为起点,dis[v]即为s到v的最短距离,pre[w]为v前驱。w是边j的长度,且i连接u、v。
初始化:dis[s]=0,dis[v]=∞(v≠s),pre[s]=0
for(i=1;i<=n-1;i++)
for (j=1;j<=M:j++)
//注意要枚举所有边,不能枚举点。
if(dis[u[j]]+w[j]<dis[v[j]])
{
//u[j]、[v]分别是这条边连接的两个起点与终点。
dis[v[j]]=dis[u[j]]w[j];
pre[v[j]]=u[j];//疏通路径
}
核心思想:看看能否通过w]这条边,使得1号顶点到们号顶点的距离变短。
枚举完一次所有边为一次松弛,那么需要松弛多少次呢?
至多n-1次,通常可能在n-1次前结束;
所以可以在每一次松弛做一个标记,如果这次松弛已经没有可以改变的值了就可结束了;
for(i=1;i<=n-1;i++)
{
int check=0
for (j=1;j<=M:j++)
{
//注意要枚举所有边,不能枚举点。
if(dis[u[j]]+w[j]<dis[v[j]])
{
//u[j]、[v]分别是这条边连接的两个起点与终点。
dis[v[j]]=dis[u[j]]w[j];
check=1;
}
}
if(ckeck==0)break;//没有改变了
}
2.SPFA算法——队列优化的bellman-ford算法
SPFA是Bellman-Ford算法的一种队列实现,减少了不必要的冗余计算。
主要思想是:
初始时将起点加入队列。每次从队列中取出一个元素,并对所有与它相邻的点进行修改,若某个相邻的点修改成功,则将其入
队。直到队列为空时算法结束。
这个算法,简单的说就是队列优化的bellman-ford,利用了每个点不会更新次数太多的特点发明的此算法。
SP℉A在形式上和广度优先搜索非常类似,不同的是广度优先搜索中一个点出了队列就不可能重新进入队列,但是SPFA中一个
点可能在出队列之后再次被放入队列,也就是说一个点修改过其它的点之后,过了一段时间可能会获得更短的路径,于是再次
用来修改其它的点,这样反复进行下去。
算法时间复杂度:O(kE),E是边数。K是常数,平均值为2。
void SPFA(int t)
{
queue<int>q;
memset(dis,0x3f,sizeof(dis));
dis[t]=0;
q.push(t);
vis[t]=1;
while(!q.empty())
{
int cur=q.front();
q.pop();
vis[t]=0;
for(int i=head[cur];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
if(dis[v>dis[cur]+w])
{
dis[cur]=dis[cur]+w;
if(vis[v]==0)
{
q.push(v);
vis[v]=1;
}
}
}
}
}
用的前向星存储图;
vis数组用来判断点是否在队列中;