【最短路径】:Dijkstra算法、SPFA算法、Bellman-Ford算法和Floyd-Warshall算法
求最短路径最常用的算法有:
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算法相关推荐
- 最短路径Dijkstra算法和Floyd算法整理、
转载自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html 最短路径-Dijkstra算法和Floyd算法 Dijks ...
- 【Java数据结构与算法】第二十章 Dijkstra算法和Floyd算法
第二十章 Dijkstra算法和Floyd算法 文章目录 第二十章 Dijkstra算法和Floyd算法 一.Dijkstra算法 1.介绍 2.代码实现 二.Floyd算法 1.介绍 2.代码实现 ...
- DP之Warshall算法和Floyd算法
DP之Warshall算法和Floyd算法 上2篇详细分析了动态规划的一些理解,传统的教材上就大概说了下空间换时间,记忆以避免重复计算等. 然后我们在文章中深入的分析和解释了交叠子问题是怎么表现的,最 ...
- 算法设计(动态规划实验报告) 基于动态规划的背包问题、Warshall算法和Floyd算法
一.名称 动态规划法应用 二.目的 1.掌握动态规划法的基本思想: 2.学会运用动态规划法解决实际设计应用中碰到的问题. 三.要求 1.基于动态规划法思想解决背包问题(递归或自底向上的实现均可): 2 ...
- 最长不下降子序列的O(n^2)算法和O(nlogn)算法
转帖 最长不下降子序列的O(n^2)算法和O(nlogn)算法 最长不下降子序列(LIS:Longest Increasing Subsequence) //用句通俗的话说,我讲的很通俗易懂~~ 问题 ...
- C++floyd warshall算法求最短路径(附完整源码)
C++floyd warshall算法求最短路径 floyd warshall算法求最短路径的完整源码(定义,实现,main函数测试) floyd warshall算法求最短路径的完整源码(定义,实现 ...
- WordCount作业提交到FileInputFormat类中split切分算法和host选择算法过程源码分析
参考 FileInputFormat类中split切分算法和host选择算法介绍 以及 Hadoop2.6.0的FileInputFormat的任务切分原理分析(即如何控制FileInputForm ...
- 06 聚类算法 - 代码案例二 - K-Means算法和Mini Batch K-Means算法比较
03 聚类算法 - K-means聚类 04 聚类算法 - 代码案例一 - K-means聚类 05 聚类算法 - 二分K-Means.K-Means++.K-Means||.Canopy.Mini ...
- KNN算法和Kernel KNN算法的区别
KNN算法和Kernel KNN算法的区别 KNN算法 KNN(K-Nearest Neighbor,简称KNN)算法,是一种常用的监督学习方法,其工作机制为:给定测试样本,基于某种距离度量找出训练集 ...
- 贪心算法和01背包算法
贪心算法和01背包算法 实验报告 1.问题 2.解析 3.设计 4.分析 5.源码 实验报告 课程名称 <算法分析与设计> 实验名称 贪心算法和01背包算法 1.问题 [描述算法问题,首选 ...
最新文章
- 「AutoML」激活函数如何进行自动学习和配置
- Linux2.6内核中链表的实现
- 域名注册商标_科技述说:一起了解网络域名的由来
- [ZJOI2007]棋盘制作
- 正则至少一个数字_好程序员web前端培训分享JavaScript学习笔记之正则
- javascript框架比较(四)
- Android java和C的Socket通信demo(可用)
- SnapKit 是怎样炼成的 | 掘金技术征文
- 各地的公安接口的配置说明书
- Openstack版本查看
- canvas图片合成模糊变清晰的方法
- android7.0 投屏,流水断崖安卓投屏
- 9x9九宫格java_数独9x9九宫格的口诀 9×9数独技巧
- 新国标下的2020年电动单车企业蓬勃发展
- 五粮液前三季净赚173亿背后:Q3净利增速下滑,3大流通股东减持
- 英语影视台词---经典电影台词(世间万物有始皆有终。)
- 高等代数--双线性空间与辛空间
- Google Maven Replacer Plugin插件详解
- 浅谈Android中的Fragment
- Qt 动态实时显示波形图