BFS算法虽然可以求解最短路径问题,但是需要注意的是该算法只能求解非带权图的单源最短路径问题,或者说带权值相同且为1的图单源最短路径问题。

1、图的邻接矩阵存储结构定义

#define MaxVerNum 100            //顶点数目的最大值
typedef struct{char Vex[MaxVerNum];     //顶点表int Edge[MaxVerNum][MaxVerNum];    //邻接矩阵,边表int vexnum,archnum;              //图的当前顶点数和弧数
}Graph;

2、图的邻接表存储结构定义

#define MaxVerNum 100            //顶点数目的最大值
typedef struct ArcNode{           //边表结点 int adjvex;                  //该弧所指向的顶点的位置struct ArcNode *next;        //指向下一条弧的指针 int num;                    //图的权值
}ArcNode;
typedef struct VNode{           //顶点表信息 char data;                  //顶点信息 ArcNode *first;              //指向第一条依附于该顶点的弧的指针
}VNode,AdjList[MaxVerNum];
typedef struct{AdjList vertices;            //邻接表int vexnum,arcnum;             //图的顶点数和弧数
}Graph;

3、BFS算法求解非带权图的单源最短路径

//BFS算法求解非带权图单源最短路径问题
void BFS_MIN_Distance(Graph G,int u)    //求到u的单源最短路径
{for(int i=0;i<G.vexnum;i++){d[i]=INF;         //初始化路径长度path[i]=-1;       //初始化到达每个顶点的前驱结点 }    visit[u]=true;d[u]=0;            //自身到自身的距离为0 EnQueue(Q,u);while(!isEmpty(Q)){DeQueue(Q,u);for(w=FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w)){if(!visit[w]){visit[w]=true;d[w]=d[u]+1;         //路径长度加1 path[w]=u;           //最短路径是从u到w EnQueue(Q,w);       //w入队 }}}
} 

由于BFS算法的应用局限,所以对于带权值(正值)的图, 我们需要求解其单源最短路径的时候,就可以使用Dijkstra算法。

单源最短路径是指:图中某一顶点到其他各顶点的最短路径。

4、Dijkstra算法的定义

Dijsktra算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层扩展,直到扩展到终点为止。在无向图G=(V,E)中,假设每条边E[i]的长度为w[i],找到由顶点v0到其余各点的最短路径。

5、Dijkstra算法的基本思想

1、把路径长度递增次序产生最短路径算法。

2、把V分为两组:

S:已求出最短路径的顶点的集合,初始时S中只有一个源点,以后每求得一条最短路径就将其加入到集合S中,直到所有顶点都加入到S中;

V-S=T:尚未确定最短路径的顶点集合;

3、将T中顶点按最短路径递增的次序加入到S中,保证:从源点V0到S中各顶点的最短路径长度都不大于从V0到T中任何顶点的最短路径长度。

4、每个顶点对应一个距离值:

S中顶点:从V0到此顶点的最短路径长度;

T中顶点:从V0到此顶点的只包括S中顶点作中间顶点的最短路径长度;

6、具体实现过程

首先将其全部初始化为无穷大(除了源点到源点之外):

在表中选择一个路径最短的点a,从a出发,a到自己的距离是0,它往外有三条边,更新a到b,c,d的最短距离,此时a被标记,则此后a都不会再被访问,此时该表更新为:

再在这张表中选择一个最短距离,是A->B,选出B作为新的起点,它有两条边分别是到达C,E,由于从B到C的距离是2,则从源点经过B到达C的最短距离是3,比之前的要小,所以更新最短距离,这时B也被标记,B不会再被访问。

再在这张表中选择一个最短距离,从AàC,则选择C点作为新的起点,从C出发有2条边,分别到达D,E,由于从A经过C到E的最短距离是23,小于之前的51,所以更新最短距离,从A经过C到达D的最短距离是8,小于之前的10,更新最短距离,则此时C被标记,C之后便不会再被访问。

再在这张表中选择一个最短距离,从A->D,所以选择D作为新的起点,从D只有一条边,到达E,则此时从A经过B,C,D到达E的最短距离是11,小于之前的23,所以更新最短距离,则此时D被标记,D不会再被访问。

再在这张表中选择一个最短距离,只有A->E,由于它并没有没访问的边,所以循环跳出,整个遍历结束!

所以这个有向图的单源最短路径是0,1,3,8,11。

再需要更新最短路径的时候,使用数组tar记录下到达当前顶点的前一个顶点,也就是最佳路径的弧尾和弧头。然后使用深度优先遍历递归查找每个顶点到源点的最短路径。

7、给出Dijkstra算法求解单源最短路径的实例

【问题描述】

给定一个n个顶点,m条有向边的带非负权图,请计算从s出发,到图中各点的距离。

【输入输出及示例】

输入:顶点数n,边数m,源点s,m条边以(p,q,weight)形式输入,分别表示弧尾、弧头和弧长;

输出:源点到每个点的距离,同时输出源点到每个点的路径。

示例1:

输入:顶点数:7,边数:10,源点:1

弧尾、弧头、弧长为:

1 2 13

1 3 8

1 5 30

1 7 32

2 6 9

2 7 7

3 4 5

4 5 6

5 6 2

6 7 17

输出:源点到顶点1的最短路径长度是:0

源点到顶点1的最短路径是:1

源点到顶点2的最短路径长度是:13

源点到顶点2的最短路径是:1 2

源点到顶点3的最短路径长度是:8

源点到顶点3的最短路径是:1 3

源点到顶点4的最短路径长度是:13

源点到顶点4的最短路径是:1 3 4

源点到顶点5的最短路径长度是:19

源点到顶点5的最短路径是:1 3 4 5

源点到顶点6的最短路径长度是:21

源点到顶点6的最短路径是:1 3 4 5 6

源点到顶点7的最短路径长度是:20

源点到顶点7的最短路径是:1 2 7

 代码:

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define INF 0X3F3F3F3F//使用链式存储边,建图
struct node{int begin;  //边的始点 int end;    //边的终点 int cost;   //边的代价 int next;   //当前边的下一条相邻边
}e[1010]; int head[1010];   //head[i]存储与该点相邻的边
int dis[1010];    //存放源点到每个点的最短距离
int visit[1010];  //标记哪些点被访问,访问的点被设为1
int tar[1010];    //追踪最短路径void dfs(int s,int v)   //输出最短路径
{if(s==v)    //递归到源点,输出源点 {cout<<s<<" ";return ;}dfs(s,tar[v]);     //一直寻找到达该点的路径 cout<<v<<" ";
}
int main()
{int n,m,s;cout<<"请输入顶点的个数、边的条数以及源点的位置: ";cin>>n>>m>>s;cout<<"请输入每条边的起点、始点和代价:"<<endl;for(int i=1;i<=m;i++)   //存储边,建图 {cin>>e[i].begin>>e[i].end>>e[i].cost;int from=e[i].begin;     //记录当前是从哪个点发出 e[i].next=head[from];    //存储该点的下一条边 head[from]=i;           // 更新与该点的相邻的最后一条边(也就是当前边) } for(int i=1;i<=n;i++)  //初始化,先将每个距离设置为最大值 {dis[i]=INF;} int begin=s;dis[begin]=0;   //自己到自己的最短距离为0 while(visit[begin]!=1)  //对每个点进行查找,直至所有点被标记完 {visit[begin]=1;   //没被访问,那就访问 for(int i=head[begin];i!=0;i=e[i].next)  //依次访问与当前起点相邻的边{if(dis[e[i].end]>dis[e[i].begin]+e[i].cost)  //更新不同起点到达该点的最短距离 {dis[e[i].end]=dis[e[i].begin]+e[i].cost;tar[e[i].end]=e[i].begin;   //存储当前点的前一个点 }} int min1=INF;for(int i=1;i<=n;i++)   //每一次都寻找所有还没被标记的点中距离最小的点{if(visit[i]!=1&&dis[i]<min1){min1=dis[i];begin=i;   //以距离最小的点为新的起点,从当前点出发 }}} cout<<"源点到每个点的最短路径长度:"<<endl;for(int i=1;i<=n;i++) {cout<<"源点到顶点"<<i<<"的最短路径长度为:"<<dis[i]<<endl;if(dis[i]==INF)   //说明不可达{cout<<"该点不可达!"<<endl<<endl;} else{cout<<"源点到顶点"<<i<<"的最短路径是:";dfs(s,i);cout<<endl<<endl;}}return 0;
}

需要注意的是:Dijkstra算法虽然能求解带权图的单源最短路径问题,但是其权值只能是非负值,对于负权值该算法不一定能得到正确结果。

8、Floyd算法求各顶点之间最短路径问题

Floyd算法其实是基于动态规划的思想,在原路径中尝试加入顶点k作为中间顶点,得到的新路径与原路径长度比较,得到最短路径。

#define Maxsize 100
int path[Maxsize][Maxsize];       //记录某一顶点到另一顶点的中转矩阵
int A[Maxsize][Maxsize];          //记录从顶点i到顶点j的路径长度
//初始化准备工作,初始化矩阵A和path
for(int k=0;k<n;k++)     //列举中转点
{for(int i=0;i<n;i++)    //遍历整个矩阵的行和列 {for(int j=0;j<n;j++){if(A[i][j]>A[i][k]+A[k][j]){A[i][j]=A[i][k]+A[k][j];    //更新最短路径 path[i][j]=k;              //记录中转点 }}}
}

Floyd算法的时间复杂度为O(|V|^3),空间复杂度为O(|V|^2)。该算法可以解决图中带负权值的问题,但是其不允许包含带负权值的边组成的回路,因为这种图有可能不存在最短路径。

图的应用—求解最短路径(BFS、Dijkstra和Floyd算法)相关推荐

  1. 数据结构之图的应用:最短路径(Dijkstra、Floyd)

    图的应用:最短路径 思维导图: 最短路径的定义: BFS算法:(无权单源最短路径) Dijkstra算法:(无权单源.带权单源) Dijkstra算法原理: 算法实现中的辅助数组: 例: 如何通过pa ...

  2. 最短路径的求解方法(Dijkstra、Floyd算法)

    用带权的有向图表示一个交通运输网,图中: 顶点--表示城市 边--表示城市间的交通联系 权--表示此线路的长度或沿此线路运输所花的时间或费用等 问题:从某顶点出发,沿图的边到达另一顶点所经过的路径中的 ...

  3. 数据结构(六):图的概念、存储方式、基本操作、最小生成树、最短路径、有向无环图、关键路径 | Prim、Kruskal算法 | BFS、Dijkstra、Floyd算法 | 拓扑排序 | 求关键路径

    文章目录 第六章 图 一.图 (一)图的定义 (二)图逻辑结构的应用 (三)无向图.有向图 (四)简单图.多重图 (五)顶点的度.入度.出度 (六)顶点-顶点的关系描述 (七)连通图.强连通图 (八) ...

  4. 图论算法之最短路径(Dijkstra、Floyd、Bellman-ford和SPFA)

    图论算法之最短路径(Dijkstra.Floyd.Bellman-ford和SPFA) 1.图论最短路径概述 图论算法为了求解一个顶点到另一个顶点的最短路径,即如果从图中某一顶点(称为源点)到达另一顶 ...

  5. 图的单源最短路径:Dijkstra算法实现

    本文介绍的是图的非负权值的单源最短路径问题.问题的提出是,对于有权图D,t提供源点v,要找到从v到其他所有点的最短路径,即单源最短路径问题,在本文中,解决这一问题,是普遍比较熟悉的Dijkstra算法 ...

  6. 最短路径算法——Dijkstra and Floyd算法

    一.     前言:     这个古老的算法应该耳熟能详了吧,但是我自从从学校出来到现在,最短路径算法都没有实际运用过,最近在一个GIS项目中总算用到了,于是乎把教材重温了下,同时查阅了网上很多的资料 ...

  7. 最短路径模板+解析——(FLoyd算法)

    对于无权的图来说: 若从一顶点到另一顶点存在着一条路径,则称该路径长度为该路径上所经过的边的数目,它等于该路径上的顶点数减1. 由于从一顶点到另一顶点可能存在着多条路径,每条路径上所经过的边数可能不同 ...

  8. 图的单源最短路径(Dijkstra算法)

    单源最短路径问题 如果从图中某一顶点(源点)到达另一顶点(终点)的路径可能不止一条,如何找到一条路径使得沿此路径各边上的权值总和达到最小. Dijkstra算法由来 迪杰斯特拉算法(Dijkstra) ...

  9. 【最短路径问题笔记】Floyd算法求多源最短路径问题

      代码: 使用邻接矩阵建图 使用邻接矩阵存放最短距离 #include<iostream> #include<cstring> using namespace std; co ...

最新文章

  1. 在家搭建大数据分布式计算环境!
  2. Netty的引用计数对象
  3. 3.4.1 计算机网络之流量控制(停止-等待协议、滑动窗口、后退N帧协议GBN、选择重传协议SR)、滑动窗口、可靠传输机制
  4. POJ - 1741 Tree(点分治模板题)
  5. Android开发之通过ImageView名称从文件夹拿到ImageView的Drawable对象的方法
  6. TensorFlow基本计算单元——变量
  7. Offer年薪低于25W全额退款|阿里、腾讯内推快艇《全链路大数据分析工程师》课程招生简章...
  8. iframe内部内容在浏览窗口位置固定的问题
  9. 用计算机编码原理解释,编码原理
  10. 读取MySQL二进制文件_MYSQL: mysqlbinlog读取二进制文件报错read_log_event()
  11. PopupWindow点击空白区域消失
  12. Python基础之字符串
  13. Window XP驱动开发(十一) USB2.0 芯片CY7C68013A+FPGA实现的高速传输系统设计(软件及硬件)
  14. word页码任意设置,如显示在页脚外侧、横版页面要求显示在左侧或右侧
  15. 【文摘】2008年度_Atom处理器
  16. C语言 猜数游戏 首先由计算机产生一个随机数,并给出这个随机数所在的区间,然后有游戏者猜测这个数。猜中游戏结束,并可以重新挑战,猜错重新给出提示,如果猜测超过八次游戏失败。
  17. 【金猿人物展】树根互联COO黄路川:从“灯塔工厂”到“数字领航”,工业互联网操作系统助推新型工业化...
  18. 2-1:编写一个Java应用程序,输出俄文字母表。
  19. 技嘉主板命名规则是什么
  20. Python程序设计基础(第2版)by董付国 习题答案

热门文章

  1. 讲讲 Maven 依赖
  2. [2019BUAA软件工程]个人期末总结感想
  3. linux上wds部署服务,WDS服务器的部署与配置
  4. uniapp的物理返回键
  5. 三个月前第一星期一Oracle,ORACLE日期函数
  6. Bootstrap之移动设备优先、栅格系统、媒体查询,响应式式布局
  7. AIGC教育(续篇):探索掌握AIGC,引领未来的人才之路
  8. 机器视觉(图像处理)入门金典之图像数字化及处理方法
  9. 彩色图像、灰度图像、二值图像和索引图像区别
  10. C printf格式化输入输出 %lu