别说了,世界那么大我想去看看!(最短路径-迪杰斯特拉算法弗洛伊德算法)
前言:
一直想去外面的世界看看,中国城市那么多,那么美,怎么样才可以用最少的钱,最短的时间游遍我想去的城市呢?(我在做梦?不不不!迪杰斯特拉算法和弗洛伊德算法来了)
这两个算法有着广泛的用途,让我们来康康:
(***后附代码演示哦!!!*** )
多么厉害的应用啊,那么让我们来一起学习吧!
一、迪杰斯特拉算法(Dijkstra)
首先说说迪杰斯特拉算法的求解过程:
- 对于网N=(V,E),将N中的顶点分成两组:
- 第一组 S:已求出的最短路径的终点集合(初始时只包含源点v0)
- 第二组V-S:尚未求出的最短路径的顶点集合(初始时为V-{v0})
- 算法将按各顶点与v0间最短路径长度递增的次序,逐个将集合V-S中的顶点加入到集合S中去。在这个过程中,总保持v0到集合S中各顶点的路径长度始终不大于到集合V-S中各顶点的路径长度。
总结归纳:首先我们知道,这点很重要!
在这条路径上,必定只含一条边,并且这条边是所有从源点v0出发的所有边中权值最小的一条。那么你想,到其它边最小的,肯定要经过之前最小的邻接边,所以核心思想我们可以说成是依各条最短路径的长度递增的次序依次求得各条路径。
- 下一条路径长度次短的最短路径的特点:
- (假设其终点为vk)
- 它只可能有两种情况:
或者是直接从源点到该顶点的边: <v0vk> (只含一条边);
或者是,从源点经过顶点u,再到达该顶点的两条边组成: <v0 u> < u vk>。
- 依次类推:
- 一般情况下,下一条最短路径的特点: 它或者是直接从源点直达该顶点的一条弧;
或者是,从源点经过已求得了最短路径的顶点集合中的顶点,再到达该顶点。
算法步骤:
这里需要知道存储结构一点知识有: 邻接矩阵G[n][n] (或者邻接表) 辅助数组: 数组S[n]: 记录相应顶点是否已求出最短路径
数组D[n]: 记录当前所求出的从源点到相应顶点的最短路径长度 数组Path[n]: 记录相应顶点路径中的前驱顶点
(1)初始化:
- 将源点v0加到S中,即S[v0]=true;
- 将v0到各个终点的最短路径长度初始化为权值,即D[i]=G.arcs[v0][vi],(vi∈V-S);
- 如果v0和顶点vi之间有弧,则将vi的前驱置为v0,即Path[i]=v0,否则Path[i]=-1。
(2)循环n-1次,执行以下操作: - 选择下一条最短路径的终点vk,使得:
D[k]=Min{D[i]|vi∈V-S} - 将vk加到S中,即S[k]=true;
- 根据条件更新从v0出发到集合V-S上任一顶点的最短路径的长度,若条件D[k]+G.arcs[k][i]<D[i]成立,则更新D[i]=D[k]+G.arcs[k][i],同时更改vi的前驱为vk;Path[i]=k。
为了更好的理解,将上面的总结就是:
1.初始化:先找出从源点v0到各终点vk的直达路径(v0,vk),即通过一条弧到达的路径。
2.选择:从这些路径中找出一条长度最短的路径(v0,u)。
3.更新:然后对其余各条路径进行适当调整:
判断:若在图中存在弧(u,vk),且(v0,u)+(u,vk)<(v0,vk),
则以路径(v0,u,vk)代替(v0,vk)。
在调整后的各条路径中,再找长度最短的路径,
依此类推。
看这个例子更好的理解:
求这个图的最短路径就有:
二、弗洛伊德算法
迪杰斯特拉是从一个点到其余各点的最短路径,二弗洛伊德则是每对顶点之间的最短路径。这个时候聪明的你是不是想到调用迪杰斯特拉算法呢?一起来看看趴
弗洛伊德算法的基本思想是:
从 vi 到 vj 的所有可能存在的路径中,选出一条长度最短的路径
算法:
若<vi,vj>存在,则存在路径{vi,vj}
// 路径中不含其它顶点
若<vi,v1>,<v1,vj>存在,则存在路径{vi,v1,vj}
// 路径中所含顶点序号不大于1
若{vi,…,v2}, {v2,…,vj}存在,
则存在一条路径{vi, …, v2, …vj}
// 路径中所含顶点序号不大于2
…
依次类推,则 vi 至 vj 的最短路径应是上述这些路径中,路径长度最小者。
****下面演示代码:
迪杰斯特拉算法:
//算法 迪杰斯特拉算法#include <iostream>
using namespace std;#define MaxInt 32767 //表示极大值,即∞
#define MVNum 100 //最大顶点数
typedef char VerTexType; //假设顶点的数据类型为字符型
typedef int ArcType; //假设边的权值类型为整型int *D=new int[MVNum]; //用于记录最短路的长度
bool *S=new bool[MVNum]; //标记顶点是否进入S集合
int *Path=new int[MVNum]; //用于记录最短路顶点的前驱//------------图的邻接矩阵-----------------
typedef struct{VerTexType vexs[MVNum]; //顶点表ArcType arcs[MVNum][MVNum]; //邻接矩阵int vexnum,arcnum; //图的当前点数和边数
}AMGraph;int LocateVex(AMGraph G , VerTexType v){//确定点v在G中的位置for(int i = 0; i < G.vexnum; ++i)if(G.vexs[i] == v)return i;return -1;
}//LocateVexvoid CreateUDN(AMGraph &G){//采用邻接矩阵表示法,创建无向网Gint i , j , k;cout <<"请输入总顶点数,总边数,以空格隔开:";cin >> G.vexnum >> G.arcnum; //输入总顶点数,总边数cout << endl;cout << "输入点的名称:,如a" << endl;for(i = 0; i < G.vexnum; ++i){cout << "请输入第" << (i+1) << "个点的名称:";cin >> G.vexs[i]; //依次输入点的信息}cout << endl;for(i = 0; i < G.vexnum; ++i) //初始化邻接矩阵,边的权值均置为极大值MaxIntfor(j = 0; j < G.vexnum; ++j)G.arcs[i][j] = MaxInt;cout << "输入边依附的顶点及权值,如a b 7" << endl;for(k = 0; k < G.arcnum;++k){ //构造邻接矩阵VerTexType v1 , v2;ArcType w;cout << "请输入第" << (k + 1) << "条边依附的顶点及权值:";cin >> v1 >> v2 >> w; //输入一条边依附的顶点及权值i = LocateVex(G, v1); j = LocateVex(G, v2); //确定v1和v2在G中的位置,即顶点数组的下标G.arcs[i][j] = w; //边<v1, v2>的权值置为wG.arcs[j][i] = G.arcs[i][j]; //置<v1, v2>的对称边<v2, v1>的权值为w}//for
}//CreateUDNvoid ShortestPath_DIJ(AMGraph G, int v0){//用Dijkstra算法求有向网G的v0顶点到其余顶点的最短路径int v , i , w , min;int n = G.vexnum; //n为G中顶点的个数for(v = 0; v < n; ++v){ //n个顶点依次初始化S[v] = false; //S初始为空集D[v] = G.arcs[v0][v]; //将v0到各个终点的最短路径长度初始化为弧上的权值if(D[v] < MaxInt) Path [v] = v0; //如果v0和v之间有弧,则将v的前驱置为v0else Path [v] = -1; //如果v0和v之间无弧,则将v的前驱置为-1}//forS[v0]=true; //将v0加入SD[v0]=0; //源点到源点的距离为0/*―初始化结束,开始主循环,每次求得v0到某个顶点v的最短路径,将v加到S集―*/for(i = 1;i < n; ++i){ //对其余n-1个顶点,依次进行计算min= MaxInt;for(w = 0; w < n; ++w)if(!S[w] && D[w] < min){ //选择一条当前的最短路径,终点为vv = w;min = D[w];}//ifS[v]=true; //将v加入Sfor(w = 0;w < n; ++w) //更新从v0出发到集合V?S上所有顶点的最短路径长度if(!S[w] && (D[v] + G.arcs[v][w] < D[w])){D[w] = D[v] + G.arcs[v][w]; //更新D[w]Path [w] = v; //更改w的前驱为v}//if}//for
}//ShortestPath_DIJvoid DisplayPath(AMGraph G , int begin ,int temp ){//显示最短路if(Path[temp] != -1){DisplayPath(G , begin ,Path[temp]);cout << G.vexs[Path[temp]] << "-->";}
}//DisplayPathint main()
{cout << "************迪杰斯特拉算法**************" << endl << endl;AMGraph G;int i , j ,num_start , num_destination;VerTexType start , destination;CreateUDN(G);cout <<endl;cout << "*****无向网G创建完成!*****" << endl;for(i = 0 ; i < G.vexnum ; ++i){for(j = 0; j < G.vexnum; ++j){if(j != G.vexnum - 1){if(G.arcs[i][j] != MaxInt)cout << G.arcs[i][j] << "\t";elsecout << "∞" << "\t";}else{if(G.arcs[i][j] != MaxInt)cout << G.arcs[i][j] <<endl;elsecout << "∞" <<endl;}}}//forcout << endl;cout << "请依次输入起始点、终点名称:";cin >> start >> destination;num_start = LocateVex(G , start);num_destination = LocateVex(G , destination);ShortestPath_DIJ(G , num_start);cout << endl <<"最短路径为:";DisplayPath(G , num_start , num_destination);cout << G.vexs[num_destination]<<endl;return 0;
}//main
演示例子的话可以用上图哦。
弗洛伊德算法:
//算法 弗洛伊德算法#include <iostream>
using namespace std;#define MaxInt 32767 //表示极大值,即∞
#define MVNum 100 //最大顶点数typedef char VerTexType; //假设顶点的数据类型为字符型
typedef int ArcType; //假设边的权值类型为整型int Path[MVNum][MVNum]; //最短路径上顶点vj的前一顶点的序号
int D[MVNum][MVNum]; //记录顶点vi和vj之间的最短路径长度//------------图的邻接矩阵---------------
typedef struct{VerTexType vexs[MVNum]; //顶点表ArcType arcs[MVNum][MVNum]; //邻接矩阵int vexnum,arcnum; //图的当前点数和边数
}AMGraph;int LocateVex(AMGraph G , VerTexType v){//确定点v在G中的位置for(int i = 0; i < G.vexnum; ++i)if(G.vexs[i] == v)return i;return -1;
}//LocateVexvoid CreateUDN(AMGraph &G){//采用邻接矩阵表示法,创建有向网Gint i , j , k;cout <<"请输入总顶点数,总边数,以空格隔开:";cin >> G.vexnum >> G.arcnum; //输入总顶点数,总边数cout << endl;cout << "输入点的名称,如a" << endl;for(i = 0; i < G.vexnum; ++i){cout << "请输入第" << (i+1) << "个点的名称:";cin >> G.vexs[i]; //依次输入点的信息}cout << endl;for(i = 0; i < G.vexnum; ++i){ //初始化邻接矩阵,边的权值均置为极大值MaxIntfor(j = 0; j < G.vexnum; ++j){if(j != i)G.arcs[i][j] = MaxInt;elseG.arcs[i][j] = 0;}//for}//forcout << "输入边依附的顶点及权值,如a b 3" << endl;for(k = 0; k < G.arcnum;++k){ //构造邻接矩阵VerTexType v1 , v2;ArcType w;cout << "请输入第" << (k + 1) << "条边依附的顶点及权值:";cin >> v1 >> v2 >> w; //输入一条边依附的顶点及权值i = LocateVex(G, v1); j = LocateVex(G, v2); //确定v1和v2在G中的位置,即顶点数组的下标G.arcs[i][j] = w; //边<v1, v2>的权值置为w}//for
}//CreateUDNvoid ShortestPath_Floyed(AMGraph G){//用Floyd算法求有向网G中各对顶点i和j之间的最短路径int i , j , k ;for (i = 0; i < G.vexnum; ++i) //各对结点之间初始已知路径及距离for(j = 0; j < G.vexnum; ++j){D[i][j] = G.arcs[i][j];if(D[i][j] < MaxInt && i != j) Path[i][j]=i; //如果i和j之间有弧,则将j的前驱置为ielse Path [i][j] = -1; //如果i和j之间无弧,则将j的前驱置为-1}//forfor(k = 0; k < G.vexnum; ++k)for(i = 0; i < G.vexnum; ++i)for(j = 0; j < G.vexnum; ++j)if(D[i][k] + D[k][j] < D[i][j]){ //从i经k到j的一条路径更短D[i][j] = D[i][k]+D[k][j]; //更新D[i][j]Path[i][j] = Path[k][j]; //更改j的前驱为k}//if
}//ShortestPath_Floyedvoid DisplayPath(AMGraph G , int begin ,int temp ){//显示最短路径if(Path[begin][temp] != -1){DisplayPath(G , begin ,Path[begin][temp]);cout << G.vexs[Path[begin][temp]] << "-->";}
}//DisplayPathint main(){cout << "************弗洛伊德算法**************" << endl << endl;AMGraph G;char start , destination;int num_start , num_destination;CreateUDN(G);cout <<endl;cout << "有向网G创建完成!" << endl;ShortestPath_Floyed(G);cout << "请依次输入路径的起点与终点的名称:";cin >> start >> destination;num_start = LocateVex(G , start);num_destination = LocateVex(G , destination);DisplayPath(G , num_start , num_destination);cout << G.vexs[num_destination] << endl;cout << "最短路径的长度为:" << D[num_start][num_destination] << endl;cout <<endl;return 0;
}//main
后记:
这里我着重迪杰斯特拉算法,因为弗洛伊德其实本质也是一样的,如果需要了解更多可以去查阅其它资料哦。
ps别拦着我,我要去看世界了…竟然没钱!!哭了,看来巧妇难为无米之炊啊。那么我要去搬砖赚钱啦,期待下一篇博客,冲鸭,搬砖去啦!
别说了,世界那么大我想去看看!(最短路径-迪杰斯特拉算法弗洛伊德算法)相关推荐
- 最短路径之迪杰斯特拉(Dijkstra 算法)弗洛伊德算法(C语言完整代码实现)
写在前面:博主是一位普普通通的19届双非软工在读生,平时最大的爱好就是听听歌,逛逛B站.博主很喜欢的一句话花开堪折直须折,莫待无花空折枝:博主的理解是头一次为人,就应该做自己想做的事,做自己不后悔的事 ...
- 最短路径 - 迪杰斯特拉(Dijkstra)算法
对于网图来说,最短路径,是指两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点为源点,最后一个顶点为终点.最短路径的算法主要有迪杰斯特拉(Dijkstra)算法和弗洛伊德(Floyd ...
- >算法笔记-动态规划-最短路径迪杰斯特拉算法
算法笔记-动态规划-最短路径迪杰斯特拉算法 作者:星河滚烫兮 前言 图的最短路径问题在现实生活中有很广阔的应用,最短路径又分为单源最短路径与多源最短路径,前者求出固定起点到其他节点的最短路径,后者 ...
- 六、最短路径——迪杰斯特拉(Dijkstra)算法
在网图和非网图中,最短路径的含义是不同的.由于非网图它没有边上的权值,所谓的最短路径,其实就是指两顶点之间经过的边数最少的路径:而对于网图来说,最短路径,是指两顶点之间经过的边上权值之和最少的路径,并 ...
- 最短路径——迪杰斯特拉算法——图的数据结构
最短路径是在工程上经常用到的概念,在这里给出了从单源点到任意顶点的迪杰斯特拉算法. 先来看看基本概念: 用代码C语言实现如下: #include<string.h>#include< ...
- 简述dijkstra算法原理_理解最短路径——迪杰斯特拉(dijkstra)算法
1. 迪杰斯特拉算法简介 迪杰斯特拉(dijkstra)算法是典型的用来解决最短路径的算法,也是很多教程中的范例,由荷兰计算机科学家狄克斯特拉于1959年提出,用来求得从起始点到其他所有点 ...
- 最短路径(迪杰斯特拉、弗洛伊德含代码)
用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.对于⽆向图⽽⾔,最短路径就是从源点V0到终点Vn所包含的边最少的路径 迪杰斯特拉算法 从一个顶点到其 ...
- 03 优先搜索(dfs bfs)、最小生成树(笛卡尔 prime)、两点最短路径(迪杰斯特拉 Floyd)
#include<bits/stdc++.h> using namespace std; void bfs(){for(int i=1;i<=n;i++)v[i]=0;queue&l ...
- 【图】最短路径--迪杰斯特拉(Dijkdtra)算法
迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止. 算法思想 每次找到离源 ...
最新文章
- python作者龟叔_龟叔和他的Python
- 清除vc6工程中的vss
- 期末离散数学复习稳过不挂指南(更新中)
- flutter中list相关操作汇总(有这一篇就够啦)
- 汽车位置服务之kafka集群配置注意事项
- Spring配置汇总
- java安全编码指南之:字符串和编码
- 基于Python的HTTP接口测试
- TheFatRat生成免杀木马(powershell)报错问题
- abb机器人goto指令用法_abb机器人编程指令,机器人编程的程序指令
- c语言 析构函数,C++析构函数详解
- Mac重装Homebrew
- Linux命令学习-ps命令
- 怎么在pdf上编辑文字内容
- 计算机组成及linux基础
- 斗地主洗牌发牌——排序版
- Android属于绑定服务特点是,Android P HIDL服务绑定模式与直通模式的分析 (原创)
- 《生命科学50讲》课程笔记10-自由意志
- 爬虫--08:移动端数据的抓取
- 潍坊经贸每年单招计算机的成绩,山东经贸职业学院单招2021年春招分数线