比较:

Floyed Dijkstra(优先队列优化) SPFA(优先队列优化)
时间复杂度 o(n^3) o(n+m)(logm) o(km)
基本思想 动态规划 贪心 贪心
适用范围 无负环图 无负权图 无负环图
多源最短路 不含负权图的低复杂度解 含负权边时的单源最短路求解

1.Floyed算法

变量声明:

n,N        点的数量

m, M        边的数量

G[ x ][ y ]        图,表示从 x 点到 y 点的边的权值

dis[ i ][ j ]        路径,表示当前情况下 i 点到 j 点的最短路径长度

算法简洁描述:

通过不断选取中间点来更新从点 i 到点 j 的最短路径

更新方式:

将现有的点 i 到 j 的最短距离 与 已知点 i 到中间点 k 的最小距离 + k 到 j 的路径距离 进行比较

公式表述:

dis[ i ][ j ] = min( dis[ i ][ j ] ,  dis[ i ][ k ] + G[ k ][ j ] )

循环次序:

for temp in spot:for start in spot:for end in spot:

基本实现:

目标:

读入一个含有n条边的无负环无向图,求出图中任意两点之间的最短路径

代码:

#include <bits/stdc++.h>
using namespace std;
//n->点数 m->边数
#define N 1000
#define M 2000
int n, m;
//邻接矩阵图数组
int G[N+1][N+1];
//最短路数组
int dis[N+1][N+1];
//算法内容
void Floyed()
{for(int k = 1; k <= n; k++){    //中间点 for(int i = 1; i <= n; i++){   //起始点 if(i == k) continue;for(int j = 1; j <= n; j++){ //末尾点 if(i == j) continue;dis[i][j] = min(dis[i][j], dis[i][k] + G[k][j]); }}}
}int main(void)
{memset(dis, 0x3f, sizeof(dis));scanf("%d%d", &n, &m);//读入无负环无向图 for(int i = 1; i <= m; i++){int x, y, v;scanf("%d%d%d", &x, &y, &v);G[x][y] = G[y][x] = v;}Floyed();return 0;
}

2.Dijkstra算法

变量声明:

n, N       图的点
m, M      图的边

start       起始点

INF        无穷大
链式前向星edge      x 点下标, v 边权值, next 连接点
vis[ i ]         标记从起始点到点 i 的最短路径是否已经更新
dis[ i ]         表示从起始点到点 i 的最短路径值
结构体 ty        收纳点信息,包括点下标 x 和最短路径值 dis
priority_queue<ty>q;       边权升序排列的优先队列

算法简洁描述:

以既定起点的最短路径值为 0 开始,不断地从当前已确定最短路径的点中选取dis值最小的点,用选取点去更新所有相邻点的最短路径

过程描述:

1.更新起始点 dis 为 0,将起始点的信息(下标 和 dis值) 放进优先队列

2.从优先队列中取出一个未用于更新且 dis 值最小的点信息,然后将该点信息丢出队列

3.用取出的点去更新邻近点的 dis 值,并将新更新的点的信息放进优先队列

4.重复2、3操作,直到优先队列元素为空

其实如果利用优先队列优化,而且每个队列元素拿出来用完就丢掉,就不需要判断取出的点是否曾用于更新,这里为了突出这个先决条件,特意声明

简单实例模拟(变量意义看上述):

现在求从点 1 到各点的最短路径值:

1 2 3 4 5 6 7 8
dis[1] vis[1] dis[2] vis[2] dis[3] vis[3] dis[4] vis[4] dis[5] vis[5] dis[6] vis[6] dis[7] vis[7] dis[8] vis[8]
初始化更新 起点的dis值为0,其余dis值为INF,起点最短路径已确定,vis为true
0 T INF F INF F INF F INF F INF F INF F INF F
第一次更新 与起点邻接的点有3、4、2,更新dis,vis
0 T 0+6 T 0+5 T 0+2 T INF F INF F INF F INF F
第二次更新 在已经更新的点中选取dis最小且未用于更新最短路的点4作为新的起点,更新所有能更新的最短路径,这次只有点5可更新
0 T 6 T 4 T 2 T 2+4 T INF F INF F INF F
第三次更新 选取已经更新的点中dis值最小且未用于更新最短路的点3作为起点,更新最短路
0 T 6 T 4 T 2 T 6 T 4+5 T 4+6 T INF F
第四次更新 继续按上述方式选点,出现dis相同的两点,发现选择点2已经不能更新,所以选择点5
0 T 6 T 4 T 2 T 6 T 9 T 10 T 6+7 T

与计算机跑出的结果相同:

基本实现:

目标:

读入一个含有 n 个点的无负权无向图,求出图中从起始点 start 到任意点的最短路径

代码:

#include<bits/stdc++.h>
using namespace std;
//边&点
#define N 100000
#define M 200000
int n, m, start;
//链式前向星存图
int cnt = 0, head[M+1];
struct Node{int x, v, next;
}edge[2*N+1];
void addedge(int x, int y, int v)
{edge[++cnt].v = v;edge[cnt].x = y;edge[cnt].next = head[x];head[x] = cnt;
}
//
int dis[N+1];
bool vis[N+1];
struct ty{int dis, x;bool operator < (const ty &a) const{return dis > a.dis;}
}temp;
priority_queue<ty>q;
//Dijkstra算法
void Dijkstra(int st)
{//将初始点信息放进队列dis[st] = 0;temp.dis = 0; temp.x = st;q.push(temp);//while(!q.empty()){//找到当前队列中边权最小点temp = q.top(); q.pop();int x = temp.x;if(vis[x]) continue;vis[x] = true;//利用取出的点更新最短路for(int i = head[x]; i != -1; i = edge[i].next){int node = edge[i].x;//将可更新点更新,并放进队列if(dis[node] > dis[x] + edge[i].v){dis[node] = dis[x] + edge[i].v;ty ne;ne.dis = dis[node]; ne.x = node;q.push(ne);}}}
} int main(void)
{memset(head, -1, sizeof(head));memset(dis, 0x3f, sizeof(dis));memset(vis, false, sizeof(vis));//存图scanf("%d%d", &n, &m);for(int i = 1; i <= m; i++){int x, y, v;scanf("%d%d%d", &x, &y, &v);addedge(x, y, v);addedge(y, x, v);} scanf("%d", &start); Dijkstra(start);return 0;
} 

3.SPFA算法

变量声明

n, N       图的点
m, M      图的边

start       起始点
链式前向星edge      x 点下标, v 边权值, next 连接点
vis[ i ]         标记从起始点到点 i 的最短路径是否已经更新
dis[ i ]         表示从起始点到点 i 的最短路径值
queue<int>q;       存放点下标的队列

简洁描述:

SPFA思路和过程都和Dijkstra相似,不同的是SPFA不会去研究被用于更新最短路的点dis值是否是最小的

过程描述:

1.更新起始点 dis 为 0,放进队列

2.从队列中取出一个点

3.用取出的点更新所有与其相邻的点的 dis 。并且,如果当前队列中没有新更新过的点,就将新更新的点放进队列

4.重复2、3操作,直到队列为空

基本实现:

目标:

读入一个含有 n 个点的无负权无向图,求出图中从起始点 start 到任意点的最短路径

代码:

#include<bits/stdc++.h>
using namespace std;
//边&点
#define N 100000
#define M 200000
int n, m, start;
//链式前向星存图
int cnt = 0, head[M+1];
struct Node{int x, v, next;
}edge[2*N+1];
void addedge(int x, int y, int v)
{edge[++cnt].v = v;edge[cnt].x = y;edge[cnt].next = head[x];head[x] = cnt;
}
//
int dis[N+1];
bool vis[N+1];
queue<int>q;
//SPFA
void spfa(int st)
{//起点初始化,放进队列 dis[st] = 0; vis[st] = 1;q.push(st);while(!q.empty()){//拿出队首元素 int x = q.front(); q.pop();vis[x] = false;//更新最短路径值 for(int i = head[x]; i != -1; i = edge[i].next){int ne = edge[i].x;if(dis[ne] > dis[x] + edge[i].v){dis[ne] = dis[x] + edge[i].v;//如果该元素现在不在队列,放进队列 if(!vis[ne]){q.push(ne);vis[ne] = true;}}}}
}
int main(void)
{memset(dis, 0x3f, sizeof(dis));memset(vis, false, sizeof(vis));memset(head, -1, sizeof(head));//存图scanf("%d%d", &n, &m);for(int i = 1; i <= m; i++){int x, y, v;scanf("%d%d%d", &x, &y, &v);addedge(x, y, v);addedge(y, x, v);} scanf("%d", &start); spfa(start);//输出计算结果 for(int i = 1; i <= n; i++){printf("dis %d: %2d    ", i, dis[i]);if(i %2 == 0) cout <<endl;} return 0;
} 

三种求最短路算法基本描述及实现(C++)相关推荐

  1. 三种求平方根的算法——C/C++

    1.二分法 这种是最简单的,就是定义一个最小值0和最大值number,把一个数取一个中间值(0+number)/2,然后平方,如果平方大于该数值,就把中间值赋给最大值,否者就把中间值赋给最小值,一直循 ...

  2. pca算法python代码_三种方法实现PCA算法(Python)

    主成分分析,即Principal Component Analysis(PCA),是多元统计中的重要内容,也广泛应用于机器学习和其它领域.它的主要作用是对高维数据进行降维.PCA把原先的n个特征用数目 ...

  3. 实现二叉树的三种非递归遍历算法

    [问题描述] 编写程序,实现二叉树的三种非递归遍历算法:先序非递归,中序非递归,后序非递归. [输入形式] 输入建树序列. [输出形式] 输出三种遍历序列. [样例输入] A B C # # # # ...

  4. 漫画:三种 “奇葩” 的排序算法

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 在算法的世界里,有许多高效率的排序算法,比如快速排序.归并排序.桶 ...

  5. 四种求最大公约数算法

    四种求最大公约数算法 1. 题目 运行最大公约数的常用算法,并进行程序的调式与测试,要求程序设计风格良好,并添加异常处理模块(如输入非法等). 分析最大公约数的4种算法,补充完整算法, 进行程序的调式 ...

  6. [pascal]对“求1-100之间的所有素数”的三种不同循环结构算法的分析

    在做第四章(循环结构程序设计)的作业时,有一道"求1-100之间的所有素数"的题目,有意思的是最后出现了三种不同的写法,这三种写法的基本思想都差不多但其核心算法不同,做过求素数算法 ...

  7. pca算法python实现_三种方法实现PCA算法(Python)

    主成分分析,即Principal Component Analysis(PCA),是多元统计中的重要内容,也广泛应用于机器学习和其它领域.它的主要作用是对高维数据进行降维.PCA把原先的n个特征用数目 ...

  8. python中pca算法_Python使用三种方法实现PCA算法

    主成分分析(PCA) vs 多元判别式分析(MDA) PCA和MDA都是线性变换的方法,二者关系密切.在PCA中,我们寻找数据集中最大化方差的成分,在MDA中,我们对类间最大散布的方向更感兴趣. 一句 ...

  9. spwm控制算法c语言实现,三种SPWM波形生成算法的分析与实现

    标签: SPWM SPWM(Sinusoidal PWM)法是一种比较成熟的,目前使用较广泛的PWM法.前面提到的采样控制理论中的一个重要结论:冲量相等而形状不同的窄脉冲加在具有惯性的环节上时,其效果 ...

最新文章

  1. OSSIM系统——mysql的使用
  2. Git - Tutorial官方【转】
  3. MyBatis学习总结一
  4. OS / Linux / clone、fork、vfork 与 pthread_create 创建线程有何不同
  5. 15-多容器复杂应用的部署
  6. PyCharm 配置 Git 教程
  7. 数据库习题(填空题二)
  8. SQL语句查询今天、昨天、近7天、近30天、一个月内、上一月 数据
  9. Java实现简单电子邮件的发送
  10. Java实验—四子棋进阶
  11. 微信支付之微信公众号网页支付(各种总结)
  12. UOJ #455.【UER #8】雪灾与外卖 堆模拟费用流
  13. 802.11协议:wifi
  14. 如何在 SubSystem for Android 上安装应用?
  15. python数据提取和合并_用Python提取和合并Excel数据
  16. Java实例类中的切面_Spring进行面向切面编程的一个简单例子
  17. Python学习:批量转换图片格式-PNG转JPG
  18. 一文彻底搞懂执行上下文、VO、AO、Scope、[[scope]]、作用域链、闭包
  19. C语言(四):程序流程结构
  20. 我对雷达技术的认识与思考

热门文章

  1. APP性能测试——启动耗时测试
  2. html视频怎么改大小,视频画面尺寸重置-视频画面大小调整的方法哪个好,视频尺寸怎么修改...
  3. 手把手教你如何批量修改视频尺寸
  4. Delta tuning(只抓核心)
  5. 无人驾驶仿真软件PanoSim:(1)介绍
  6. TypeError: argument of type ‘NoneType‘ is not iterable
  7. C++ OpenCV(一):图像读取与保存
  8. 6-dw_元数据管理
  9. Coursera | Introduction to Data Science in Python(University of Michigan)| Assignment1
  10. 递归与lamdba与高阶函数