最短路算法的SPFA算法

来源:互联网 发布:高中地理优化设计 编辑:程序博客网 时间:2024/05/22 17:02

看见很多人写的博客,有很多很详细的过程还有具体的图的解释,但是好像没看见什么博客把自己的思路写出来的代码做一个详细的解释(我也是听很多师哥的讲解,然后写的代码),所以就在这里把代码做一个更详细的解释。


特点:

可以处理负边,只要最短路径存在,就一定可以求出最小值

判断有无负环:如果某点进入队列的次数超过N次,则存在负环(该算法无法处理带负环的图)

负回路:该图所有权值得和小于零,则形成了负回路。


模板代码:

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
#define N 1000000
const int inf=0x3f3f3f3f;
int nodeNum,edgeNum;//结点的数量和边的数量;
int d[N];//数组d[i]表示源点s到i的距离
int c[N];//统计每一个结点入队的次数
bool vis[N];
bool loop;//判断是否有回路
map[nodeNum][nodeNum];//存之间的点
void spfa(int start)//先传入开始的点
{
    queue<int>q;//建立队列,初始化几个数组
    memset(vis,false,sizeof(vis))//false代表还没有入队
    for(int i=1;i<=nodeNum;i++)
        dis[i]=inf;//先把之间的距离初始化为最大值
    dis[start]=true;//源点初始化为真
    q.push(start);//源点入队
    vis[start]=1;//源点标记为1
}
while(!q.empty())//判断队列是否为空,如果为空,则说明已经遍历完毕
{//入队时要用vis数组标记一下
    int temp=q.front();
    q.pop();//取走队头的元素
    vis[q]=flase;//取走后再出队,消除标记
    for(int i=1;i<=nodeNum;i++)
    {
        if(dis[temp]+map[temp][i]<dis[i])//和之前算法一样的松弛操作
        {
            dis[i]=dis[temp]+map[temp][i];
            if(!vis[i])//判断相邻的结点是否在队列中
            {
                q.push(i);
                vis[i]=true;
            }
        }
    }

}


但是这个算法不是很稳定,期望的时间复杂度O(ke),其中k为所有顶点进队的平均次数,k一般小于等于2;


算法的优化方法:

1),SLF优化:

当你要向队列中添加结点的时候,现将其与队首元素进行比较,如果比当前已知的最短距离更小一些,那么将其放在队首的位置,否则放到队尾。

2),LLL优化

设队首元素为i,队列中所有dis的平均值为x,若dis>x,则将i插入到队尾,查找下一个元素,知道dia<=i,,则出队进行松弛操作。




0 0
原创粉丝点击