图论最短路径算法——SPFA
为了不要让太多人被害,我还是说一下这种算法,它实际上很简单,但被人讲着讲着绕晕了。
主要思想
有人说,SPFA是Bellman-Ford的队列优化。这个算法我也懂了,但是还没试过。我不管是什么算法的优化,反正我看着不像。
它的思想很简单:BFS。有人说这只是类似的,并不是纯BFS。我不管这些,分这么严格干嘛呢!
从起点开始,枚举它节点的边,走所有与它相连的路径。如果能更新别的节点就更新,不能更新嘛,就直接将它从队列里删掉,不要它了,反正它没鬼用。
还有一点,要标记某节点是否已经在队列里,将一个节点加入时,看看它在不在队列里面,如果在,就不用放进去,反正没鬼用。
若某个点在队列里出现过N次,则是进入了负环,赋个无限小就行了。
实现讲解
先讲讲图的存储。这个图并不是用邻接矩阵来弄的(你也能用,速度会慢,也许还会出现溢出等奇怪的错误)。这个东西叫邻接表,有的人也叫它边集数组。就是记录每一个节点,与它相连的所有的边。每条边的信息有这个点的另一端,已及这条边的权值。
我是这样定义的
struct _Way//定义_Way类型,表示某点与y点相连,长度为len
{
int y,len;
};
_Way way[1001][1001] {};//way[i][j]标示i的第j条路
int now[1001] {};//now[i]即为节点i所连的边的数量 Number of ways
当然,你也可以开动态数组。不过如果不是急需省内存,你就开吧。但是我没试过,也许会更繁琐。
读入时也许读入重边,用指针判断判断就好了
正常的BFS不用说了吧。。。
判断一个节点是否在队列中,只需要一个数组标记就好了。
具体代码
#include <iostream>
#include <string.h>
#include <math.h>
#include <limits.h>
using namespace std;
struct _Way//定义_Way类型,表示某点与y点相连,长度为len
{
int y,len;
};
int n,m;
int q;
_Way way[1001][1001] {};//way[i][j]标示i的第j条路
_Way* bz[1001][1001] {};//输入时用于判断,有时输入了重边,肯定要取最小的,这个标记了这个边的地址,方便判断
int now[1001] {};//now[i]即为节点i所连的边的数量 Number of ways
int dis[1001] {};//dis[i]即为从起点到i的最短距离
int min(int a,int b){return a<b?a:b;}//取最小值函数
void SPFA(int);
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y,len;
cin>>x>>y>>len;
if (bz[x][y]!=NULL)//判断这条边是否重了
{
bz[x][y]->len=min(bz[x][y]->len,len);//如果重了边取最小值
continue;
}
now[x]++;
way[x][now[x]].y=y;
way[x][now[x]].len=len;
bz[x][y]=&(way[x][now[x]]);//将它的地址赋给bz[x][y]
}
cin>>q;
SPFA(q);
for(int i=1;i<=n;i++)
{
if (dis[i]==INT_MAX) cout<<"-1"<<endl;//如果到不了输出-1
else cout<<dis[i]<<endl;
}
return 0;
}
void SPFA(int q)//q表示起点
#define SIZE 2006
{
bool bz[1001] {};//bz[i]表示i节点是否在队列中
for(int i=1;i<=n;i++)
dis[i]=INT_MAX;//初始化为无限大
int head=0,tail=1;
int d[SIZE+1];
dis[q]=0;//起点到起点,当然为0了
d[1]=q;
bz[q]=1;
do
{
head++;
if (head>SIZE) head=1;//与下文一样,用循环队列
for(int i=1;i<=now[d[head]];i++)//将跟它相连的边都枚举一遍
{
tail++;
if (tail>SIZE) tail=1;
d[tail]=way[d[head]][i].y;
if (dis[d[tail]]<=dis[d[head]]+way[d[head]][i].len)//如果现在到那边不比之前的优,则删掉它
{
tail--;
if (tail<1) tail=SIZE;
continue;
}
dis[d[tail]]=dis[d[head]]+way[d[head]][i].len;//更新
if (bz[d[tail]])
{
tail--;
if (tail<1) tail=SIZE;
continue;
}
bz[d[tail]]=1;//标记其以进入队列
}
bz[d[head]]=0;//它出了队列,将之前的1改为0
}
while (head!=tail);
}
优化
图论最短路径算法——SPFA的更多相关文章
- 图论最短路径算法总结(Bellman-Ford + SPFA + DAGSP + Dijkstra + Floyd-Warshall)
这里感谢百度文库,百度百科,维基百科,还有算法导论的作者以及他的小伙伴们...... 最短路是现实生活中很常见的一个问题,之前练习了很多BFS的题目,BFS可以暴力解决很多最短路的问题,但是他有一定的 ...
- 图论最短路径算法——Dijkstra
说实在的,这算法很简单,很简单,很简单--因为它是贪心的,而且码量也小,常数比起SPFA也小. 主要思想 先初始化,dis[起点]=0,其它皆为无限大. 还要有一个bz数组,bz[i]表示i是否确定为 ...
- 几大最短路径算法比较(Floyd & Dijkstra & Bellman-Ford & SPFA)
几个最短路径算法的比较:Floyd 求多源.无负权边(此处错误?应该可以有负权边)的最短路.用矩阵记录图.时效性较差,时间复杂度O(V^3). Floyd-Warshall算法(Floyd ...
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较
几大最短路径算法比较 转自:http://blog.csdn.net/v_july_v/article/details/6181485 几个最短路径算法的比较: Floyd 求多 ...
- (最短路径算法整理)dijkstra、floyd、bellman-ford、spfa算法模板的整理与介绍
这一篇博客以一些OJ上的题目为载体.整理一下最短路径算法.会陆续的更新... 一.多源最短路算法--floyd算法 floyd算法主要用于求随意两点间的最短路径.也成最短最短路径问题. 核心代码: / ...
- 几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较(转)
几大最短路径算法比较 几个最短路径算法的比较:Floyd 求多源.无负权边(此处错误?应该可以有负权边)的最短路.用矩阵记录图.时效性较差,时间复杂度O(V^3). Floy ...
- 图论-最短路径 2.Dijkstra算法O (N2)
2.Dijkstra算法O (N2) 用来计算从一个点到其他所有点的最短路径的算法,是一种单源最短路径算法.也就是说,只能计算起点只有一个的情况. Dijkstra的时间复杂度是O (N2),它不能处 ...
- Cocos2d-x 地图步行实现1:图论Dijkstra算法
下一节<Cocos2d-x 地图行走的实现2:SPFA算法>: http://blog.csdn.net/stevenkylelee/article/details/38440663 本文 ...
- [联赛可能考到]图论相关算法——COGS——联赛试题预测
COGS图论相关算法 最小生成树 Kruskal+ufs int ufs(int x) { return f[x] == x ? x : f[x] = ufs(f[x]); } int Kruskal ...
随机推荐
- LeetCode刷题笔记-回溯法-括号生成
题目描述: 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合. 例如,给出 n = 3,生成结果为: [ "((()))", "( ...
- 20140309 C++ using 野指针 返回变量首地址
1.C++中的using:http://blog.sina.com.cn/s/blog_61e904fd0100nuk3.html 使用using恢复.改变被继承类中的访问权限 2.野指针,没有指向的 ...
- solr 如何实现精确查询
第一条和第三条不应该出现的. 解决办法
- 循环神经网络RNN
转自 http://blog.csdn.net/xingzhedai/article/details/53144126 更多参考:http://blog.csdn.net/mafeiyu80/arti ...
- 《转》python 9 字典,numpy
http://www.cnblogs.com/BeginMan/p/3156960.html 一.映射类型 我理解中的映射类型是:键值对的关系,键(key)映射值(value),且它们是一对多的关系. ...
- Activiti学习笔记10 — 动态任务分配
动态任务分配使用的两种方式 一.通过特殊表达式,来获取任务信息 ,在流程 UserTask节点上设置 ${流程变量的Key} 1.流程定义 <?xml version="1.0&quo ...
- JS事件 文本框内容改变事件(onchange)通过改变文本框的内容来触发onchange事件,同时执行被调用的程序。
文本框内容改变事件(onchange) 通过改变文本框的内容来触发onchange事件,同时执行被调用的程序. 如下代码,当用户将文本框内的文字改变后,弹出对话框"您改变了文本内容!&quo ...
- LeetCode动态规划题总结【持续更新】
以下题号均为LeetCode题号,便于查看原题. 10. Regular Expression Matching 题意:实现字符串的正则匹配,包含'.' 和 '*'.'.' 匹配任意一个字符,&quo ...
- 深度探索C++对象模型之第一章:关于对象之关键词所引起的差异
————如果不是为了努力维护与C之间的兼容性,C++远比现在简单的多. 如果一个程序员渴望学习C++,但是他却发现书中没有熟悉的struct,一定会苦恼,将这个主题包含到C++里,可以提供语言转移时的 ...
- 在vue项目引入阿里巴巴矢量图标
1.在阿里矢量图标库将想要的图标加入购物车,然后在购物车中将图标添加到项目: 2.到我的项目中,将图标下载到本地 3.在vue项目的assets文件夹下新建一个iconfont文件夹(名字自定义),将 ...