求最短路径最常用的算法有:
Dijkstra算法、SPFA算法、Bellman-Ford算法和Floyd-Warshall算法。
Dijkstra算法、SPFA算法、Bellman-Ford算法这三个求单源最短路径,最后一个Floyd-Warshall算法可以求多源最短路径也可以求单源路径,效率比较低。
SPFA算法是Bellman算法的队列优化。
Dijkstra算法不能求带负权边的最短路径,而SPFA算法、Bellman-Ford算法、Floyd-Warshall可以求带负权边的最短路径。
Bellman-Ford算法的核心代码只有4行,Floyd-Warshall算法的核心代码只有5行。

1.最基本的求单源最短路径方法是图的深度优先遍历:

用 min = 99999999 记录路径的最小值,book[i]标记结点 i 是否被访问过~

#include <iostream>
using namespace std;
int minn = 99999999;
int book[101];
int n;
int e[101][101];//cur是当前所在的城市编号,dis是当前已经走过的路程
void dfs(int cur, int dis) {if (dis > minn)return ;if (cur == n) {if (dis < minn)minn = dis;return ;}for (int i = 1; i <= n; i++) {//从cur到所有结点依次尝试if (e[cur][i] != 99999999 && book[i] == 0) {book[i] = 1;dfs(i, dis + e[cur][i]);//从i结点出发到其他所有结点依次尝试直到遇到要求的n结点为止book[i] = 0;}}return ;
}int main() {int m;cin >> n >> m;int a, b, c;for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (i == j)e[i][j] = 0;elsee[i][j] = 99999999;}}for(int i = 1; i <= m; i++) {cin >> a >> b >> c;e[a][b] = c;}book[1] = 1;dfs(1, 0);cout << minn;return 0;
}

2.单源最短路径:Dijkstra算法
dis[i]是需要不断更新的数组,它表示当前结点1(源点)到其余各结点的最短路径长度~
book[i]标记当前结点最短路径是确定值还是估计值~
算法实现的过程是:每次找到离结点1最近的那个点,然后以该结点为中心扩展,最终得到源点到所有点的最短路径~~每次新扩展一个距离最短的点,更新与其相邻的点的距离。当所有边权都为正时,由于不会存在一个距离更短的没扩展过的点,所以这个点的距离永远不会再被改变,因而保证了算法的正确性。不过根据这个原理,用Dijkstra求最短路的图不能有负权边,因为扩展到负权边的时候会产生更短的距离,有可能就破坏了已经更新的点距离不会改变的性质~~
找到所有估计值当中最小的值min以及它的结点u,然后把该结点u标记为确定值,通过这个确定值为中转点更新别的所有值的最短路径(松弛别的两个顶点连接的边)

#include <iostream>
using namespace std;
int main() {// 建立二维数组储存结点和边的信息int n, m;cin >> n >> m;int e[10][10];for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (i == j)e[i][j] = 0;elsee[i][j] = 99999999;}}int t1, t2, t3;for (int i = 1; i <= m; i++) {cin >> t1 >> t2 >> t3;e[t1][t2] = t3;}// dis数组保存结点1其余结点的最短路径int dis[10];for (int i = 1; i <= n; i++) {dis[i] = e[1][i];}// book表示dis数组中的内容是估计值还是确定值int book[10];for (int i = 1; i <= n; i++) {book[i] = 0;}book[1] = 1;// book == 0 表示是估计值,book == 1 表示是确定值int u = 1, minn;//Dijkstra算法核心语句for (int i = 1; i <= n - 1; i++) {minn = 99999999;for (int j = 1; j <= n; j++) {if (book[j] == 0 && dis[j] < minn) {minn = dis[j];u = j;}}book[u] = 1; //在所有估计值中找到最小的值,把它标记为确定值for (int v = 1; v <= n; v++) {if (e[u][v] < 99999999) {if (dis[u] + e[u][v] < dis[v])dis[v] = dis[u] + e[u][v];}}//通过这个确定值为中转点更新别的所有值的最短路径(松弛别的两个顶点连接的边)}//print resultfor (int i = 1; i <= n; i++)cout << dis[i] << " ";return 0;
}

3.Bellman-Ford算法——解决负权边
算法思想:对所有的边进行n-1次“松弛”操作

核心算法四行:
for (k = 1; k <= n - 1; k++)for (i = 1; i <= m; i++)if (dis[v[i]] > dis[u[i]] + w[i])dis[v[i]] = dis[u[i]] + w[i];
进行n-1轮的原因:在一个含有n个顶点的图中,任意两点之间的最短路径最多包含n-1边。//检验负权回路
如果在进行最短路径算法后,仍然有可以松弛的边,那么就是存在负权回路
flag = 0;
for (i = 1; i <= m; i++)if (dis[v[i]] > dis[u[i]] + w[i])flag = 1;
if (flag == 1)printf("此图含有负权回路");
如果在新一轮的松弛中数组dis没有发生变化,则可以提前跳出循环
#include <iostream>
#include <cstdio>
//n个结点,m条边
using namespace std;
int main() {int dis[10], bak[10], n, m, u[10], v[10], w[10], check, flag;int inf = 99999999;scanf("%d %d", &n, &m);for (int i = 1; i <= m; i++)scanf("%d %d %d", &u[i], &v[i], &w[i]);for (int i = 1; i <= n; i++)dis[i] = inf;dis[1] = 0;for (int k = 1; k <= n - 1; k++) {for (int i = 1; i <= n; i++)bak[i] = dis[i];//将dis数组备份入bak数组中,为了下面的检查是否更新而进行剪枝for (int i = 1; i <= m; i++)if (dis[v[i]] > dis[u[i]] + w[i])dis[v[i]] = dis[u[i]] + w[i];check = 0;for (int i = 1; i < n; i++)if (bak[i] != dis[i]) {check = 1;break;}// 如果对于所有的结点,dis的值都没有被更新,那就提前跳出循环,说明不需要进行n-1次了if (check == 0)break;}//检查是否含有负权回路(可省略)flag = 0;for (int i = 1; i <= m; i++)if (dis[v[i]] > dis[u[i]] + w[i])flag = 1;if (flag == 1)printf("此图含有负权回路");else {for (int i = 1; i <= n; i++) printf("%d ", dis[i]);}return 0;
}

4.Bellman-Ford的队列优化(SPFA算法)
每次选取首顶点u,对u的所有出边进行松弛操作~如果有一条u->v的边,通过这条边使得源点到顶点v的路程变短,且顶点v不在当前队列中,就把这个顶点v放入队尾。同一个顶点在队列中出现多次是毫无意义的,所以用一个数组来判重复,判断哪些点已经在队列中。对顶点u的所有出边都松弛完毕后,就将顶点v出队~

#include <iostream>
#include <cstdio>
using namespace std;
int main() {int n, m;int u[8], v[8], w[8];int first[6], next[8];int dis[6] = {0}, book[6] = {0};int que[101] = {0};int head = 1;int tail = 1;int inf = 99999999;scanf("%d %d", &n, &m);for (int i = 1; i <= n; i++)dis[i] = inf;dis[1] = 0;for (int i = 1; i <= n; i++)book[i] = 0;for (int i = 1; i <= n; i++)first[i] = -1;for (int i = 1; i <= m; i++) {scanf("%d %d %d", &u[i], &v[i], &w[i]);next[i] = first[u[i]];first[u[i]] = i;}que[tail] = 1;tail++;book[1] = 1;int k;while (head < tail) {k = first[que[head]];while (k != -1) {if (dis[v[k]] > dis[u[k]] + w[k]) {dis[v[k]] = dis[u[k]] + w[k];if (book[v[k]] == 0) {que[tail] = v[k];tail++;book[v[k]] = 1;}}k = next[k];}book[que[head]] = 0;head++;}for (int i = 1; i <= n; i++)printf("%d ", dis[i]);return 0;
}

【最短路径】:Dijkstra算法、SPFA算法、Bellman-Ford算法和Floyd-Warshall算法相关推荐

  1. 最短路径Dijkstra算法和Floyd算法整理、

    转载自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html 最短路径-Dijkstra算法和Floyd算法 Dijks ...

  2. 【Java数据结构与算法】第二十章 Dijkstra算法和Floyd算法

    第二十章 Dijkstra算法和Floyd算法 文章目录 第二十章 Dijkstra算法和Floyd算法 一.Dijkstra算法 1.介绍 2.代码实现 二.Floyd算法 1.介绍 2.代码实现 ...

  3. DP之Warshall算法和Floyd算法

    DP之Warshall算法和Floyd算法 上2篇详细分析了动态规划的一些理解,传统的教材上就大概说了下空间换时间,记忆以避免重复计算等. 然后我们在文章中深入的分析和解释了交叠子问题是怎么表现的,最 ...

  4. 算法设计(动态规划实验报告) 基于动态规划的背包问题、Warshall算法和Floyd算法

    一.名称 动态规划法应用 二.目的 1.掌握动态规划法的基本思想: 2.学会运用动态规划法解决实际设计应用中碰到的问题. 三.要求 1.基于动态规划法思想解决背包问题(递归或自底向上的实现均可): 2 ...

  5. 最长不下降子序列的O(n^2)算法和O(nlogn)算法

    转帖 最长不下降子序列的O(n^2)算法和O(nlogn)算法 最长不下降子序列(LIS:Longest Increasing Subsequence) //用句通俗的话说,我讲的很通俗易懂~~ 问题 ...

  6. C++floyd warshall算法求最短路径(附完整源码)

    C++floyd warshall算法求最短路径 floyd warshall算法求最短路径的完整源码(定义,实现,main函数测试) floyd warshall算法求最短路径的完整源码(定义,实现 ...

  7. WordCount作业提交到FileInputFormat类中split切分算法和host选择算法过程源码分析

    参考 FileInputFormat类中split切分算法和host选择算法介绍  以及 Hadoop2.6.0的FileInputFormat的任务切分原理分析(即如何控制FileInputForm ...

  8. 06 聚类算法 - 代码案例二 - K-Means算法和Mini Batch K-Means算法比较

    03 聚类算法 - K-means聚类 04 聚类算法 - 代码案例一 - K-means聚类 05 聚类算法 - 二分K-Means.K-Means++.K-Means||.Canopy.Mini ...

  9. KNN算法和Kernel KNN算法的区别

    KNN算法和Kernel KNN算法的区别 KNN算法 KNN(K-Nearest Neighbor,简称KNN)算法,是一种常用的监督学习方法,其工作机制为:给定测试样本,基于某种距离度量找出训练集 ...

  10. 贪心算法和01背包算法

    贪心算法和01背包算法 实验报告 1.问题 2.解析 3.设计 4.分析 5.源码 实验报告 课程名称 <算法分析与设计> 实验名称 贪心算法和01背包算法 1.问题 [描述算法问题,首选 ...

最新文章

  1. 「AutoML」激活函数如何进行自动学习和配置
  2. Linux2.6内核中链表的实现
  3. 域名注册商标_科技述说:一起了解网络域名的由来
  4. [ZJOI2007]棋盘制作
  5. 正则至少一个数字_好程序员web前端培训分享JavaScript学习笔记之正则
  6. javascript框架比较(四)
  7. Android java和C的Socket通信demo(可用)
  8. SnapKit 是怎样炼成的 | 掘金技术征文
  9. 各地的公安接口的配置说明书
  10. Openstack版本查看
  11. canvas图片合成模糊变清晰的方法
  12. android7.0 投屏,流水断崖安卓投屏
  13. 9x9九宫格java_数独9x9九宫格的口诀 9×9数独技巧
  14. 新国标下的2020年电动单车企业蓬勃发展
  15. 五粮液前三季净赚173亿背后:Q3净利增速下滑,3大流通股东减持
  16. 英语影视台词---经典电影台词(世间万物有始皆有终。)
  17. 高等代数--双线性空间与辛空间
  18. Google Maven Replacer Plugin插件详解
  19. 浅谈Android中的Fragment
  20. Qt 动态实时显示波形图

热门文章

  1. Android studio for mac
  2. 【JAQS】jaqs与DataCore 框架安装,学习笔记(一)
  3. 《ANTLR 4权威指南》——第2章纵观全局
  4. spring整合ehcache
  5. Dijstra算法-------为了纪念,等以后看的时候方便
  6. dwz框架在网站群项目中的应用(2)—html拓展之页面形式
  7. jquery选择器小知识点们
  8. Struts,Hibernate,Spring经典面试题收藏(转)
  9. 网络主机和交换机端口位置的有效定位方法
  10. 工业互联网巨头 GE Digital 修复SCADA 软件中的两个高危漏洞