本来我是想把这两个算法分开写描述的,但是SPFA其实就是Dijkstra的稀疏图优化,所以其实代码差不多,所以就放在一起写了。

  因为SPFA是Dijkstra的优化,所以我想来讲讲Dijkstra。

  什么是Dijkstra

  Dijkstra是一种求单源最短路的基础算法,时间复杂度在不加堆优化的情况下是o(n^2)的,加了堆优化就能简化到o(nlogn),而且算法稳定性很强(从这点上来说比SPFA好多了,具体怎么好下面再讲),基础思路如下:

  首先,把所有点到源的距离设为最大,然后把源加入队列,接着每次对队列首做这种操作:用邻接表找到从这个点能链到的所有所有点,接着要按大小顺序找当前距离和当前队首最近的点(这个按大小顺序就是可以用堆优化的地方),做松弛操作,松弛成功,将这个点入队,否则按大小顺序找下一条边,然后重复做松弛操作,直到当前点所有能链到的边松弛过,弹出当前点,重复以上操作,直到队列里没有其他元素。结束程序,输出单源到某点距离。

  加了堆优化之后,有如此6的复杂度的Dijkstra,一般来说就是稳定单源最短路的最佳程序,但是在全图有负环的时候,Dijkstra算法就显得很无力了,在这时,我们就要用SPFA这种神奇的乱搞算法了。

  什么是SPFA

  SPFA算法全称是Shortest Path Faster Algorithm算法,人家都叫“Faster”了,那肯定有过人之处,基础思路如下:

  首先,还是把所有点到源的距离设为最大,把源加入队列,接着每次对队首做这种操作:用邻接表找到从这个点能链到的所有所有点,然后对每条边做松弛操作,只要松弛成功,我们就判断当前松弛成功的点是否在队列,如果不在,就入队,否则就只是做松弛,然后弹出当前点,对下一点再次做以上操作,直到队列为空。

  当然,和Dijkstra相比,SPFA看起来相当的乱搞,但是,对于绝大多数(稀疏)图来说,加了SLF和LLL两种优化的SPFA肯定比Dijkstra快得多(SLF和LLL就是两种决策优化,前者对于最值优化,后者是均值优化)。

  顺带附上一道codevs1021的SPFA题目与代码

  麦克找了个新女朋友,玛丽卡对他非常恼火并伺机报复。

    因为她和他们不住在同一个城市,因此她开始准备她的长途旅行。

    在这个国家中每两个城市之间最多只有一条路相通,并且我们知道从一个城市到另一个城市路上所需花费的时间。

    麦克在车中无意中听到有一条路正在维修,并且那儿正堵车,但没听清楚到底是哪一条路。无论哪一条路正在维修,从玛丽卡所在的城市都能到达麦克所在的城市。

    玛丽卡将只从不堵车的路上通过,并且她将按最短路线行车。麦克希望知道在最糟糕的情况下玛丽卡到达他所在的城市需要多长时间,这样他就能保证他的女朋友离开该城市足够远。

编写程序,帮助麦克找出玛丽卡按最短路线通过不堵车道路到达他所在城市所需的最长时间(用分钟表示)。

输入描述 Input Description

第一行有两个用空格隔开的数N和M,分别表示城市的数量以及城市间道路的数量。1≤N≤1000,1≤M≤N*(N-1)/2。城市用数字1至N标识,麦克在城市1中,玛丽卡在城市N中。

接下来的M行中每行包含三个用空格隔开的数A,B和V。其中1≤A,B≤N,1≤V≤1000。这些数字表示在A和城市B中间有一条双行道,并且在V分钟内是就能通过。

 

输出描述 Output Description

   输出文件的第一行中写出用分钟表示的最长时间,在这段时间中,无论哪条路在堵车,玛丽卡应该能够到达麦克处,如果少于这个时间的话,则必定存在一条路,该条路一旦堵车,玛丽卡就不能够赶到麦克处。

样例输入 Sample Input

5 7

1 2 8

1 4 10

2 3 9

2 4 10

2 5 1

3 4 7

3 5 10

样例输出 Sample Output

27

  题解如下

  这道题关键在于最优解可能会无法连通,所以我们求出最优解之后,要枚举最优解中哪条路会断,取其中最坏情况(题目所需),得答案就好,因为算次优解一定不能使数据再包括最优解的某条边,不然就和最优解一样了,所以以上方法是正确的。

  贴出代码

 #include<stdio.h>
struct shit{
int aim;
int get;
int next;
int lon;
}e[];
int max(int x,int y)
{
return x>y?x:y;
}
int pre[];
int d[],a,b,n,m,num,star,ass,quq[],point,head[],ans;
bool f[];
void fuck(int x,int y,int s)//建边
{
e[++point].aim=x;
e[point].lon=s;
e[point].get=y;
e[point].next=head[y];
head[y]=point;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&num);
fuck(a,b,num);
fuck(b,a,num);
}
quq[++star]=;
ass=;
f[]=true;
for(int i=;i<=n;i++)
d[i]=;
while(star<=ass)
{
for(int k=head[quq[star]];k!=;k=e[k].next)
if(d[quq[star]]+e[k].lon<d[e[k].aim])
{
d[e[k].aim]=d[quq[star]]+e[k].lon;
pre[e[k].aim]=k;//第一次的SPFA要记录路径(点的位置)
if(!f[e[k].aim])
{
quq[++ass]=e[k].aim;
f[e[k].aim]=true;
}
}
f[quq[star++]]=false;
}
ans=max(d[n],ans);
int q=n;
while(q!=)
{
a=e[pre[q]].lon;
e[pre[q]].lon=;//直接设置当前边数值极大(即设置为不连通)
if(pre[q]%==)//根据读入边的方法来双向删边
e[pre[q]+].lon=;
else
e[pre[q]-].lon=;
star=;
for(int i=;i<=ass;i++)
quq[i]=;
quq[star]=;
ass=;
f[]=true;
for(int i=;i<=n;i++)
{
d[i]=;
f[i]=false;
}
while(star<=ass)
{
for(int k=head[quq[star]];k!=;k=e[k].next)
if(d[quq[star]]+e[k].lon<d[e[k].aim])
{
d[e[k].aim]=d[quq[star]]+e[k].lon;
if(!f[e[k].aim])
{
quq[++ass]=e[k].aim;
f[e[k].aim]=true;
}
}
f[quq[star++]]=false;
}
if(d[n]!=)ans=max(d[n],ans);//如果数值就为我们设置的最大,即切去当前边的图无法连通
e[pre[q]].lon=a;
if(pre[q]%==)//复原切去的边
e[pre[q]+].lon=a;
else
e[pre[q]-].lon=a;
q=e[pre[q]].get;
}
printf("%d",ans);
return ;
}

  PS:没有加LLL和SLF的主要原因是我还不会打→_→

图论算法》关于SPFA和Dijkstra算法的两三事的更多相关文章

  1. 图论算法(四)Dijkstra算法

    最短路算法(三)Dijkstra算法 PS:因为这两天忙着写GTMD segment_tree,所以博客可能是seg+图论混搭着来,另外segment_tree的基本知识就懒得整理了-- Part 1 ...

  2. 单源最短路径算法——Bellman-ford算法和Dijkstra算法

     BellMan-ford算法描述 1.初始化:将除源点外的所有顶点的最短距离估计值 dist[v] ← +∞, dist[s] ←0; 2.迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V ...

  3. 最短路径算法-迪杰斯特拉(Dijkstra)算法在c#中的实现和生产应用

    迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先遍历思想),直到扩展到终点为止 贪心算法(Greedy ...

  4. 图论最短路径算法总结(Bellman-Ford + SPFA + DAGSP + Dijkstra + Floyd-Warshall)

    这里感谢百度文库,百度百科,维基百科,还有算法导论的作者以及他的小伙伴们...... 最短路是现实生活中很常见的一个问题,之前练习了很多BFS的题目,BFS可以暴力解决很多最短路的问题,但是他有一定的 ...

  5. 经典算法题每日演练——第十七题 Dijkstra算法

    原文:经典算法题每日演练--第十七题 Dijkstra算法 或许在生活中,经常会碰到针对某一个问题,在众多的限制条件下,如何去寻找一个最优解?可能大家想到了很多诸如“线性规划”,“动态规划” 这些经典 ...

  6. 一步一步深入理解Dijkstra算法

    先简单介绍一下最短路径: 最短路径是啥?就是一个带边值的图中从某一个顶点到另外一个顶点的最短路径. 官方定义:对于内网图而言,最短路径是指两顶点之间经过的边上权值之和最小的路径. 并且我们称路径上的第 ...

  7. 最短路经算法简介(Dijkstra算法,A*算法,D*算法)

    据 Drew 所知最短路经算法现在重要的应用有计算机网络路由算法,机器人探路,交通路线导航,人工智能,游戏设计等等.美国火星探测器核心的寻路算法就是采用的D*(D Star)算法. 最短路经计算分静态 ...

  8. 图的最短路径-----------Dijkstra算法详解(TjuOj2870_The Kth City)

    做OJ需要用到搜索最短路径的题,于是整理了一下关于图的搜索算法: 图的搜索大致有三种比较常用的算法: 迪杰斯特拉算法(Dijkstra算法) 弗洛伊德算法(Floyd算法) SPFA算法 Dijkst ...

  9. 图的最短路径---迪杰斯特拉(Dijkstra)算法浅析

    什么是最短路径 在网图和非网图中,最短路径的含义是不一样的.对于非网图没有边上的权值,所谓的最短路径,其实就是指两顶点之间经过的边数最少的路径. 对于网图,最短路径就是指两顶点之间经过的边上权值之和最 ...

随机推荐

  1. 2017年终巨献阿里、腾讯最新Java程序员面试题,准备好进BAT了吗

    Java基础 进程和线程的区别: Java的并发.多线程.线程模型: 什么是线程池,如何使用? 数据一致性如何保证:Synchronized关键字,类锁,方法锁,重入锁: Java中实现多态的机制是什 ...

  2. 压缩感知Compressive sensing(一)

    compressive sensing(CS) 又称 compressived sensing ,compressived sample,大意是在采集信号的时候(模拟到数字),同时完成对信号压缩之意. ...

  3. SGU 507 Treediff

    这个题目  其实可以暴力  用两个 set 合并: 每次放进去一个元素只要找到这个元素第一个比他大的元素和最后一个比他小的元素:然后更新最优值: 证明为什么不会超时:  假如最后集合的小的为 S1,大 ...

  4. 2018年总结和2019年的Flag

    ---恢复内容开始--- 目前截止到现在工作将近一年半了,今天工作上主要后端主要是用了两种语言,java和Python(2.7),今年完成主要的工作主要使用Python在写一些脚本来满足财务和人资部门 ...

  5. bzoj 2119 股市的预测 —— 枚举关键点+后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2119 思路就是对于这个形如 ABA 的串,枚举 A 的长度,并按照长度分出几块,找到一些关键 ...

  6. 定时任务&&找出两个list的不同

    /*-------------------------application-context.xml------------------------------*/ <?xml version= ...

  7. spring mvc静态资源访问的配置

    如果我们使用spring mvc来做web访问请求的控制转发,那么默认所有访问都将被DispatcherServlet独裁统治.比如我现在想访问的欢迎页index.html根本无需任何业务逻辑处理,仅 ...

  8. php redis 常用方法

    一些php redis 常用的方法: 1.hGet($key,$hashKey) Redis Hget 命令用于返回哈希表中指定字段的值. <?php $redis = new redis(); ...

  9. MVC FileDownLoad

    public ActionResult MatDownload() { string ShopId = Session["ShopId"].ToString(); var self ...

  10. 让memcached分布式

    memcached是应用最广的开源cache产品,它本身不提供分布式的解决方案,我猜想一方面它想尽量保持产品简单高效,另一方面cache的key-value的特性使得让memcached分布式起来比较 ...