最短单源路径算法——SPFA
来源:互联网 发布:通达信手机炒股软件 编辑:程序博客网 时间:2024/06/10 06:09
引入
毫无疑问,Dijkstra因为其简单易懂、实用可靠及不错的时间复杂度受到OI初学者的青睐,但它有一个致命缺点:无法处理边权值为负的情况。
以下是博主一段优先队列优化的Dijkstra算法。
for(int i=1;i<city;i++) { int nextnode,nextmin; int numnoww; while(true) { numnoww=minnow.size(); if(numnoww==0)break;//空队列防止RE x=minnow.top(); minnow.pop(); if(!vis[x.dot])//未访问过的才被选出,否则continue { nextnode=x.dot; nextmin=x.len; break; } } if(numnoww==0)break; vis[nextnode]=true; for(int j=data[nextnode].size()-1;j>=0;j--) { int t=data[nextnode][j].dot; if(!vis[t]&&dist[t]>dist[nextnode]+data[nextnode][j].len) { dist[t]=dist[nextnode]+data[nextnode][j].len; //修改最优距离 x.dot=t; x.len=dist[t]; minnow.push(x);//入队 } } }
显然这种方法中访问一遍某个节点后该节点就被标记为已访问了。而当存在负权值边时,可能存在在访问另一负权端点时能将已访问过的端点继续优化,但因已经将vis数组修改为true而无法更新的情况。所以如果用标准Dijkstra算法做含有负权值边的问题纯粹是碰运气。
此时我们可以用SPFA算法解决该问题。SPFA算法是1994年西安交通大学段凡丁提出的Bellman Ford算法的队列优化版本,其时间复杂度为O(ME)。(看了很多算法都是外国人提出的,国人创造的算法很自豪有木有(っ•̀ω•́)っ )。
SPFA算法主要思想
1.将除起点的其他点的距离(dist)初始化为INF,将起点初始为0,保证后续步骤能优化至最优。
2.先将起点push入队列,队首元素出列优化与起点相连的所有点的dist值。若比之前的dist值小且当前队列里没有该点则将该点push入队列。
3.重复出队队首元素,优化与之相连的点,直至队列中没有元素,则所有点到起点的距离已优化至最优。
显然SPFA中相同点可以多次加入队列,保证了有负权边存在的情况下dist的最优值。
博主以以下题目为例题:
http://ybt.ssoier.cn:8088/problem_show.php?pid=1379
为了实现这一操作,我们需要如下变量:
queue <int> next;//算法核心,用来存储下一步搜索节点;手写队列当然也可以int dist[2505];//储存起点到某个点的距离;bool now[2505];//检测当前队列中是否有某个点存在;struct sd{ int nextnode;//保存可以到的点 int len;//保存到此点的距离};sd x;//方便进行push操作vector <sd> data[2505];//保存各点数据
贴上主程序代码,讲解见注释:
//int main(){ memset(now,false,sizeof(now));//初始化为未访问 memset(dist,127,sizeof(dist)); //初始化为很大的数 int city,road,start,endd,a,b,c,noww,p,v; scanf("%d%d%d%d",&city,&road,&start,&endd); for(int i=1;i<=road;i++) //记录各点路径数据 { scanf("%d%d%d",&a,&b,&c); x.nextnode=b; x.len=c; data[a].push_back(x); x.nextnode=a; data[b].push_back(x); } next.push(start);//将起点push入队列 now[start]=true; dist[start]=0;//将自己到自己的距离改为0 while(!next.empty()) { noww=next.front();//出队 next.pop(); now[noww]=false; //注意出队后要还原为false for(int i=data[noww].size()-1;i>=0;i--) { p=data[noww][i].nextnode; v=data[noww][i].len; if(dist[p]>dist[noww]+v)//可优化 { dist[p]=dist[noww]+v; if(!now[p])//不在队列中则加入队列 { now[p]=true; next.push(p); } } } } printf("%d",dist[endd]); return 0;}
注:显然SPFA算法无法处理带有负权值环的图的最短路问题(死循环,一直在负权值环里搜索直到地老天荒…),但可以判断图中是否存在负权值环。只需再加入一个num数组计数,每次成员入队都将对应的值加一,如果某一点的入队次数超过了总点数减一,则肯定存在环,抛出异常信息。
以上就是这期博客的全部内容了,希望大家能够有所收获,也欢迎私信博主交流学习。
- 最短单源路径算法——SPFA
- 最短路径——SPFA算法
- SPFA算法——单源最短路径
- 单源最短路径 ——SPFA算法
- SPFA算法——最短路径
- 图论最短路径算法——SPFA
- SPFA算法——最短路径
- spfa算法——最短路径算法
- SPFA算法求最短路径
- 单源最短路径-spfa算法
- Spfa单源最短路径算法
- 单源最短路径:SPFA算法
- SPFA算法求单源最短路径
- 单源最短路径——Dijkstra算法,Bellman-Ford算法,SPFA算法
- 最短路径算法—SPFA(Shortest Path Faster Algorithm)算法分析与实现
- 最短路径算法—SPFA(Shortest Path Faster Algorithm)算法分析与实现(C/C++)
- 最短路径算法—SPFA(Shortest Path Faster Algorithm)算法分析与实现(C/C++)
- 最短路径算法---SPFA
- linux服务器下基于caffe的flownet搭建
- 高精度模板(减法)
- HTML小网页案例
- Confluence知识库启动报错
- 在不同的情况运行Python
- 最短单源路径算法——SPFA
- 一张思维导图,让正则表达式不再难懂
- retorfit与Rxjava的权限
- LeetCode 617. Merge Two Binary Trees
- zabbix监控日志文件
- Android的HttpUtils的网络请求OkHttp
- C/C++获取当前时刻的时分秒
- ajax 原生API
- oracle命名主键约束的原因