码迷,mamicode.com
首页 > 其他好文 > 详细

最短路--SPFA

时间:2019-08-08 23:33:29      阅读:97      评论:0      收藏:0      [点我收藏+]

标签:直接   因此   empty   不用   不成功   最短路   ini   算法   http   

 

SPFA 算法

 

算法优点

        1.时间复杂度比普通的Dijkstra和Ford

        2.能够计算负权图问题。

        3.能够判断是否有负环 (即:每跑一圈,路径会减小,所以会一直循环跑下去)。

 

 

 

 

期望的时间复杂度O(k*e), 其中k为所有顶点进队的平均次数,e是边的数量,可以证明k一般小于等于2。

 

实现方法:

  1.存入图。可以使用链式前向星或者vocter

        2.开一个队列,先将开始的节点放入。

        3.每次从队列中取出一个节点X,遍历与X相通的Y节点,查询比对  Y的长度X的长度+ X与Y的长度

            如果X的长度+ X与Y的长度 Y的长度,说明需要更新操作。

                    1).存入最短路。

                    2).由于改变了原有的长度,所以需要往后更新,与这个节点相连的最短路。(即:判断下是否在队列,在就不用重复,不在就加入队列,等待更新)。

                    3).在这期间可以记录这个节点的进队次数,判断是否存在负环。

        4.直到队空。

 

判断有无负环:如果某个点进入队列的次数超过N次则存在负环

 

 

 

模拟过程:

技术图片

 

 

首先建立起始点a到其余各点的最短路径表格

                                  技术图片

首先源点a入队,当队列非空时:

        1、队首元素(a)出队,对以a为起始点的所有边的终点依次进行松弛操作(此处有b,c,d三个点),此时路径表格状态为:

                                  技术图片

 

在松弛时三个点的最短路径估值变小了,而这些点队列中都没有出现,这些点需要入队,此时,队列中新入队了三个结点b,c,d

队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e点),此时路径表格状态为:

                                 技术图片

 

在最短路径表中,e的最短路径估值也变小了,e在队列中不存在,因此e也要入队,此时队列中的元素为c,d,e

队首元素c点出队,对以c为起始点的所有边的终点依次进行松弛操作(此处有e,f两个点),此时路径表格状态为:

                                 技术图片

 

在最短路径表中,e,f的最短路径估值变小了,e在队列中存在,f不存在。因此e不用入队了,f要入队,此时队列中的元素为d,e,f

 队首元素d点出队,对以d为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:

 

                               技术图片

在最短路径表中,g的最短路径估值没有变小(松弛不成功),没有新结点入队,队列中元素为f,g

队首元素f点出队,对以f为起始点的所有边的终点依次进行松弛操作(此处有d,e,g三个点),此时路径表格状态为:

                               技术图片

 

在最短路径表中,e,g的最短路径估值又变小,队列中无e点,e入队,队列中存在g这个点,g不用入队,此时队列中元素为g,e

队首元素g点出队,对以g为起始点的所有边的终点依次进行松弛操作(此处只有b点),此时路径表格状态为:

                           技术图片

 

在最短路径表中,b的最短路径估值又变小,队列中无b点,b入队,此时队列中元素为e,b队首元素e点出队,对以e为起始点的所有边的终点依次进行松弛操作(此处只有g这个点),此时路径表格状态为:

 

                          技术图片

 

在最短路径表中,g的最短路径估值没变化(松弛不成功),此时队列中元素为b

队首元素b点出队,对以b为起始点的所有边的终点依次进行松弛操作(此处只有e这个点),此时路径表格状态为:

                         技术图片

 

在最短路径表中,e的最短路径估值没变化(松弛不成功),此时队列为空了

最终a到g的最短路径为14

以上转载自:http://keyblog.cn/article-21.html

 

代码

int way[250][250],dis[250],vis[250],cnt[250];
//way记录路径关系,dis[i]记录起点到点j的最近距离,vis[i]标记点是否在队列中,cnt[i]记录点i进入队列的次数
int n,m;
void init()
{
    for(int i=0;i<n;i++)//先初始化way
    {
        for(int j=0;j<n;j++)
        {
            if(i==j)
                way[i][j]=0;
            else
                way[i][j]=mx;
        }
    }
}

void spfa(int st)//st是起点
{
    for(int i=0;i<n;i++)//这里点编号是从0开始的
        dis[i]=mx;
    memset(vis,0,sizeof(vis));
    memset(cnt,0,sizeof(cnt));
    vis[st]=1;
    cnt[st]=1;
    dis[st]=0;
    queue<int>p;
    p.push(st);
    while(!p.empty())
    {
        int now=p.front();
        p.pop();
        vis[now]=0;
        for(int i=0;i<n;i++)
        {
            if(dis[now]+way[now][i]<dis[i])
            {
                dis[i]=dis[now]+way[now][i];
                if(vis[i]==0)//如果点不在队列里面
                {
                    p.push(i);
                    vis[i]=1;
                    cnt[i]++;
                    if(cnt[i]>n)//如果这个点加入超过n次,说明存在负圈,直接返回 
                        return ;
                }
            }
        }
    }

}

 

模板题:https://www.cnblogs.com/-citywall123/p/11324215.html

 

最短路--SPFA

标签:直接   因此   empty   不用   不成功   最短路   ini   算法   http   

原文地址:https://www.cnblogs.com/-citywall123/p/11324246.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!