网上太多对他们的讲解了。这篇就是自己学习的一个记录。

SPFA(Shortest Path Faster Algorithm)是Bellman-Ford算法的一种队列实现,减少了不必要的冗余计算。

算法:用一个队列来进行维护。 初始时将源加入队列。 每次从队列中取出一个元素,并对所有与他相邻的点进行松弛,若某个相邻的点松弛成功,则将其入队。 直到队列为空时算法结束。

这个算法,简单的说就是队列优化的bellman-ford,利用了每个点不会更新次数太多的特点发明的此算法。SPFA——Shortest Path Faster Algorithm,它可以在O(kE)的时间复杂度内求出源点到其他所有点的最短路径,可以处理负边。SPFA的实现甚至比Dijkstra或者Bellman_Ford还要简单

SPFA可以处理负权边

定理: 只要最短路径存在,上述SPFA算法必定能求出最小值。

证明:

  每次将点放入队尾,都是经过松弛操作达到的。换言之,每次的优化将会有某个点v的最短路径估计值d[v]变小。所以算法的执行会使d越来越小。由于我们假定图中不存在负权回路,所以每个结点都有最短路径值。因此,算法不会无限执行下去,随着d值的逐渐变小,直到到达最短路径值时,算法结束,这时的最短路径估计值就是对应结点的最短路径值。

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

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

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<sstream>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#define up(i, x, y) for(int i = x; i <= y; i++)
#define down(i, x, y) for(int i = x; i >= y; i--)
#define MAXN ((int)2e4 + 10)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
struct Edge
{int v, cost;Edge(int v_ = 0, int cost_ = 0) : v(v_), cost(cost_){}
};
vector<Edge> E[MAXN];
bool vis[MAXN];
int dist[MAXN];
int cnt[MAXN];
void addedge(int u, int v, int w)
{E[u].push_back(Edge{v, w});
}
bool SPFA(int start, int n)
{memset(vis, false, sizeof(vis));for(int i = 1; i <= n; i++){dist[i] = INF;}vis[start] = true;dist[start] = 0;queue<int> que;while(!que.empty()){que.pop();}que.push(start);memset(cnt, 0, sizeof(cnt));cnt[start] = 1;while(!que.empty()){int u = que.front(); que.pop();vis[u] = false;for(int i = 0; i < E[u].size(); i++){int v = E[u][i].v;if(dist[v] > dist[u] + E[u][i].cost){dist[v] = dist[u] + E[u][i].cost;if(!vis[v]){vis[v] = true;que.push(v);if(++cnt[v] > n) return false; //超过入队次数上限,说明有负环}}}}return true;
}int main()
{int n, m;scanf("%d %d", &n, &m);up(i, 1, m){int x, y, w; scanf("%d %d %d", &x, &y, &w);addedge(x, y, w);}if(SPFA(1, n)){up(i, 2, n) printf("%d\n", dist[i]);}
}

迪杰斯特拉算法:

本质是贪心,最近的最可能最近,换句话说绕远路肯定不是最优的,所以导致没有办法求解带有负权的最短路径。因为带负权的最短路可能就是绕的远路得到的。例如:

利用迪杰斯特拉求出来的最短路为 0 4 0 , 实际为 0 2 0; 就是因为先访问的2号节点,之后没办法通过更远的3号节点去更新4号节点所以不行。这么看起来迪杰斯特拉有种BFS的感觉。

bool vis[100000 + 7];int  dis[100000 + 7];int  cnt[100000 + 7];vector<vector<P>> G;bool dijkstra(int s, int n){memset(vis, false, sizeof(vis));for(int i = 0; i < n; i++) dis[i] = 0x3f3f3f3f;vis[s] = 1;dis[s] = 0;priority_queue<P, vector<P>, greater<P>> que;que.push(P{0, s});while(!que.empty()){P cur = que.top(); que.pop();vis[cur.second] = 1;int v = cur.second;if(cur.first > dis[v]) continue; // oldfor(int i = 0; i < G[v].size(); i++){int nxt = G[v][i].first;int cost = G[v][i].second;if(vis[nxt] == 0 && dis[nxt] > dis[v] + cost ){dis[nxt] = dis[v] + cost;que.push(P{dis[nxt], nxt});}}}return 1;}

例题代码:

typedef pair<int, int> P;
class Solution {
public:bool vis[100000 + 7];int  dis[100000 + 7];int  cnt[100000 + 7];vector<vector<P>> G;bool dijkstra(int s, int n){memset(vis, false, sizeof(vis));for(int i = 0; i < n; i++) dis[i] = 0x3f3f3f3f;vis[s] = 1;dis[s] = 0;priority_queue<P, vector<P>, greater<P>> que;que.push(P{0, s});while(!que.empty()){P cur = que.top(); que.pop();vis[cur.second] = 1;int v = cur.second;if(cur.first > dis[v]) continue; // oldfor(int i = 0; i < G[v].size(); i++){int nxt = G[v][i].first;int cost = G[v][i].second;if(vis[nxt] == 0 && dis[nxt] > dis[v] + cost ){dis[nxt] = dis[v] + cost;que.push(P{dis[nxt], nxt});}}}return 1;}bool spfa(int s, int n){memset(cnt, 0, sizeof(cnt));memset(vis, false, sizeof(vis));for(int i = 0; i < n; i++){dis[i] = 0x3f3f3f3f;}vis[s] = 1;dis[s] = 0;queue<int> que;que.push(s);cnt[s] = 1;while(!que.empty()){int cur = que.front(); que.pop();vis[cur] = 0;for(int i = 0; i < G[cur].size(); i++){int v = G[cur][i].first;// cout << "v = " << v << "\n";if(dis[v] > dis[cur] + G[cur][i].second){dis[v] = dis[cur] + G[cur][i].second;if(!vis[v]){vis[v] = 1;que.push(v);if(++cnt[v] > n+1) return 0;}}}}return 1;}int minimumObstacles(vector<vector<int>>& grid) {int num = grid.size() * grid[0].size();G.resize(num);for(int i = 0; i < grid.size(); i++){for(int j = 0; j < grid[i].size(); j++){int curid = i * grid[i].size() + j;if(j < grid[i].size() - 1){int nxtid = curid + 1;G[curid].push_back(P{nxtid, grid[i][j + 1]});G[nxtid].push_back(P{curid, grid[i][j]});}if(i < grid.size() - 1){int nxtid = curid + grid[i].size();G[curid].push_back(P{nxtid, grid[i + 1][j]});G[nxtid].push_back(P{curid, grid[i][j]});}}}// spfa(0, num);dijkstra(0, num);return dis[num - 1];}
};

SPFA与迪杰斯特拉相关推荐

  1. P1462 通往奥格瑞玛的道路(二分 迪杰斯特拉 最短路 + spfa最短路算法)

    题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡奥格瑞玛 题目描述 在艾泽拉斯, ...

  2. 图论(迪杰斯特拉,Floyd,bellman,spfa)

    对图论和搜索的学习感想 Dijkstra 迪杰斯特拉求最短路的暴力的思路是三重循环去更新所有点到起点的最短距离. 首先先初始化让第一个点到自己的距离是0即: dist[1]=0; 然后在省下的点中找到 ...

  3. 迪杰斯特拉,弗洛伊德,bellman-ford和SPFA的学习笔记

    迪杰斯特拉算法 算法概念 迪杰斯特拉算法用于查找图中某个顶点到其它所有顶点的最短路径. 但是有一个点,就是用迪杰斯特拉算法时所有边的权值为非负数 如何实现算法 算法流程图 算法详解 我们讲解一下哈这个 ...

  4. 迪杰斯特拉,佛洛依德,bellman-ford和SPFA的学习笔记

    迪杰斯特拉 用途:用于解决有向图最短路径问题 创建两个数组,s和dis,s为是否为最小路径,dis为两点的距离 1(从1开始找) 2 3 4 5 6 s (初始化为F) T F F F F F dis ...

  5. usaco Sweet Butter(迪杰斯特拉(优先队列优化),bellman_ford算法模板)

    这题开始用没有优化的迪杰斯特拉喜闻乐见的超时了,然后我用bellmanford算法按理说时间复杂度更大但是书上说往往只要很短的时间就可以求出最短路. 所以我用了这个算法但是我对这个算法还是不熟套了模板 ...

  6. 迪杰斯特拉算法 两点间最短路径的选择

    百度首页 登录 注册 新闻网页贴吧知道音乐图片视频地图百科文库 首页 分类 艺术 科学 自然 文化 地理 生活 社会 人物 经济 体育 历史 特色百科 历史上的今天 数字博物馆 史记·2015 城市百 ...

  7. 迪杰斯特拉最全详解(朴素版,堆优化+邻接表存图/链式前向星存图)

    迪杰斯特拉 迪杰斯特拉算法分析 迪杰斯特拉(朴素版) 迪杰斯特拉堆优化(邻接表存图) 迪杰斯特拉堆优化(链式前向星存图) 最短路--spfa(链式前向星存图) 迪杰斯特拉算法分析 一般用三种数据结构存 ...

  8. floyd和迪杰斯特拉算法的路径记录方法。

    先说迪杰斯特拉,先看题目吧. 题目1 这题就是迪杰斯特拉的路径记录算法题啊,还记录了最小路径个数. 代码如下 #include<iostream> #include<cstdio&g ...

  9. ccf 交通规划(迪杰斯特拉优先队列模板)

    什么跟什么就是刘汝佳小白书迪杰斯特拉队列的优先队列法 #include<bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f ...

  10. 数据结构与算法(7-4)最短路径(迪杰斯特拉(Dijkstra)算法、弗洛伊德(Floyd)算法)

    目录 一.最短路径概念 二.迪杰斯特拉(Dijkstra)算法(单源最短路径) 1.原理 2.过程 3.代码 三.弗洛伊德(Floyd)算法(多源最短路径) 1.原理 2.存储 3.遍历 4.代码 参 ...

最新文章

  1. linux 查看目录挂载的ip,Linux挂载IPSAN和FCSAN操作,Linux挂载NFS文件系统
  2. Spring-Cloud中各个组件的职责
  3. 常见 Java 字节码 指令 助记符
  4. 关于scanf和cin的大数据读入效率
  5. Qt中UDP通信的简单示例
  6. shell 进入hadoop_Hadoop关于HDFS的基本操作(Shell命令)
  7. matlab如何读取csv,Matlab:如何读取CSV文件以及如何读取带有字符串数据项的CSV文件 | 学步园...
  8. 智能文档分析:NLP和OCR的融合技术
  9. mysql驱动加载原理_老调重弹:JDBC系列 之 lt;驱动载入原理全面解析gt;
  10. 腾讯终于摘掉“游戏公司”帽子!B端业务也稳了
  11. Java list.remove( )方法需要注意的地方
  12. iosTableView 局部全部刷新以及删除编辑操作
  13. edius隐藏快捷键_EDIUS 常用快捷键
  14. 编译原理-4-上下文无关文法
  15. 单位转换 inch mm mil
  16. 学习笔记:AGPS-SUPL架构
  17. perf_event 事件类型与分类
  18. Virtualbox-Ubuntu与主机(WIN7)共享文件夹设置
  19. java定时任务cron表达式每周执行一次的坑
  20. c#使用Flash控件AxShockwaveFlash时,报“未注册类”。

热门文章

  1. 项目经理:什么是矩阵型组织结构?
  2. 重磅长文!先进院李骁健等人:在体神经界面技术的发展-从小到大规模记录
  3. 信息系统项目管理师---第四章项目整体管理历年考试题
  4. 战舰世界换服务器改什么文件,战舰世界国服更新账号继承并合区,直营服已更新092...
  5. 设置VC工程为Debug或Releas版本的方法
  6. yocto之相关class总结
  7. 把JRuby Rails应用部署在Java应用服务器上
  8. 【嵌入式系统设计师笔记】——什么是嵌入式?
  9. 对数学期望、方差、协方差、协方差矩阵的理解
  10. OC中内存管理(转)