前言
Genius only means hard-working all one’s life.
Name:Willam
Time:2017/3/8

1、最短路径问题介绍

问题解释:
从图中的某个顶点出发到达另外一个顶点的所经过的边的权重和最小的一条路径,称为最短路径

解决问题的算法:

  • 迪杰斯特拉算法(Dijkstra算法)
  • 弗洛伊德算法(Floyd算法)
  • SPFA算法

之前已经对Dijkstra算法做了介绍(不懂的可以看这篇博客:Dijkstra算法详解),所以这篇博客打算对Floyd算法做详细的的介绍。

2、Floyd算法的介绍

  • 算法的特点:
    弗洛伊德算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或有向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包。

  • 算法的思路

通过Floyd计算图G=(V,E)中各个顶点的最短路径时,需要引入两个矩阵,矩阵S中的元素a[i][j]表示顶点i(第i个顶点)到顶点j(第j个顶点)的距离。矩阵P中的元素b[i][j],表示顶点i到顶点j经过了b[i][j]记录的值所表示的顶点。

假设图G中顶点个数为N,则需要对矩阵D和矩阵P进行N次更新。初始时,矩阵D中顶点a[i][j]的距离为顶点i到顶点j的权值;如果i和j不相邻,则a[i][j]=∞,矩阵P的值为顶点b[i][j]的j的值。 接下来开始,对矩阵D进行N次更新。第1次更新时,如果”a[i][j]的距离” > “a[i][0]+a[0][j]”(a[i][0]+a[0][j]表示”i与j之间经过第1个顶点的距离”),则更新a[i][j]为”a[i][0]+a[0][j]”,更新b[i][j]=b[i][0]。 同理,第k次更新时,如果”a[i][j]的距离” > “a[i][k-1]+a[k-1][j]”,则更新a[i][j]为”a[i][k-1]+a[k-1][j]”,b[i][j]=b[i][k-1]。更新N次之后,操作完成!

3、Floyd算法的实例过程

上面,我们已经介绍了算法的思路,如果,你觉得还是不理解,那么通过一个实际的例子,把算法的过程过一遍,你就明白了,如下图,我们求下图的每个点对之间的最短路径的过程如下:

第一步,我们先初始化两个矩阵,得到下图两个矩阵:

第二步,以v1为中阶,更新两个矩阵:
发现,a[1][0]+a[0][6] < a[1][6] 和a[6][0]+a[0][1] < a[6][1],所以我们只需要矩阵D和矩阵P,结果如下:

通过矩阵P,我发现v2–v7的最短路径是:v2–v1–v7

第三步:以v2作为中介,来更新我们的两个矩阵,使用同样的原理,扫描整个矩阵,得到如下图的结果:


OK,到这里我们也就应该明白Floyd算法是如何工作的了,他每次都会选择一个中介点,然后,遍历整个矩阵,查找需要更新的值,下面还剩下五步,就不继续演示下去了,理解了方法,我们就可以写代码了。

4、Floyd算法的代码实现

  • Floyd.h文件代码
/************************************************************/
/*                程序作者:Willam                          */
/*                程序完成时间:2017/3/11                   */
/*                有任何问题请联系:2930526477@qq.com       */
/************************************************************/
//@尽量写出完美的程序#pragma once
//#pragma once是一个比较常用的C/C++杂注,
//只要在头文件的最开始加入这条杂注,
//就能够保证头文件只被编译一次。/*
本博客开始对Floyd算法的使用邻接矩阵实现的
*/#include<iostream>
#include<string>
using namespace std;class Graph_DG {
private:int vexnum;   //图的顶点个数int edge;     //图的边数int **arc;   //邻接矩阵int ** dis;   //记录各个顶点最短路径的信息int ** path;  //记录各个最短路径的信息
public://构造函数Graph_DG(int vexnum, int edge);//析构函数~Graph_DG();// 判断我们每次输入的的边的信息是否合法//顶点从1开始编号bool check_edge_value(int start, int end, int weight);//创建图void createGraph(int);//打印邻接矩阵void print();//求最短路径void Floyd();//打印最短路径void print_path();
};
  • Floyd.cpp文件代码
#include"Floyd.h"//构造函数
Graph_DG::Graph_DG(int vexnum, int edge) {//初始化顶点数和边数this->vexnum = vexnum;this->edge = edge;//为邻接矩阵开辟空间和赋初值arc = new int*[this->vexnum];dis = new int*[this->vexnum];path = new int*[this->vexnum];for (int i = 0; i < this->vexnum; i++) {arc[i] = new int[this->vexnum];dis[i] = new int[this->vexnum];path[i] = new int[this->vexnum];for (int k = 0; k < this->vexnum; k++) {//邻接矩阵初始化为无穷大arc[i][k] = INT_MAX;}}
}
//析构函数
Graph_DG::~Graph_DG() {for (int i = 0; i < this->vexnum; i++) {delete this->arc[i];delete this->dis[i];delete this->path[i];}delete dis;delete arc;delete path;
}// 判断我们每次输入的的边的信息是否合法
//顶点从1开始编号
bool Graph_DG::check_edge_value(int start, int end, int weight) {if (start<1 || end<1 || start>vexnum || end>vexnum || weight < 0) {return false;}return true;
}void Graph_DG::createGraph(int kind) {cout << "请输入每条边的起点和终点(顶点编号从1开始)以及其权重" << endl;int start;int end;int weight;int count = 0;while (count != this->edge) {cin >> start >> end >> weight;//首先判断边的信息是否合法while (!this->check_edge_value(start, end, weight)) {cout << "输入的边的信息不合法,请重新输入" << endl;cin >> start >> end >> weight;}//对邻接矩阵对应上的点赋值arc[start - 1][end - 1] = weight;//无向图添加上这行代码if(kind==2)arc[end - 1][start - 1] = weight;++count;}
}void Graph_DG::print() {cout << "图的邻接矩阵为:" << endl;int count_row = 0; //打印行的标签int count_col = 0; //打印列的标签//开始打印while (count_row != this->vexnum) {count_col = 0;while (count_col != this->vexnum) {if (arc[count_row][count_col] == INT_MAX)cout << "∞" << " ";elsecout << arc[count_row][count_col] << " ";++count_col;}cout << endl;++count_row;}
}void Graph_DG::Floyd() {int row = 0;int col = 0;for (row = 0; row < this->vexnum; row++) {for (col = 0; col < this->vexnum; col++) {//把矩阵D初始化为邻接矩阵的值this->dis[row][col] = this->arc[row][col];//矩阵P的初值则为各个边的终点顶点的下标this->path[row][col] = col;}}//三重循环,用于计算每个点对的最短路径int temp = 0;int select = 0;for (temp = 0; temp < this->vexnum; temp++) {for (row = 0; row < this->vexnum; row++) {for (col = 0; col < this->vexnum; col++) {//为了防止溢出,所以需要引入一个select值select = (dis[row][temp] == INT_MAX || dis[temp][col] == INT_MAX) ? INT_MAX : (dis[row][temp] + dis[temp][col]);if (this->dis[row][col] > select) {//更新我们的D矩阵this->dis[row][col] = select;//更新我们的P矩阵this->path[row][col] = this->path[row][temp];}}}}
}void Graph_DG::print_path() {cout << "各个顶点对的最短路径:" << endl;int row = 0;int col = 0;int temp = 0;for (row = 0; row < this->vexnum; row++) {for (col = row + 1; col < this->vexnum; col++) {cout << "v" << to_string(row + 1) << "---" << "v" << to_string(col+1) << " weight: "<< this->dis[row][col] << " path: " << " v" << to_string(row + 1);temp = path[row][col];//循环输出途径的每条路径。while (temp != col) {cout << "-->" << "v" << to_string(temp + 1);temp = path[temp][col];}cout << "-->" << "v" << to_string(col + 1) << endl;}cout << endl;}
}
  • main.cpp文件的代码
#include"Floyd.h"//检验输入边数和顶点数的值是否有效,可以自己推算为啥:
//顶点数和边数的关系是:((Vexnum*(Vexnum - 1)) / 2) < edge
bool check(int Vexnum, int edge) {if (Vexnum <= 0 || edge <= 0 || ((Vexnum*(Vexnum - 1)) / 2) < edge)return false;return true;
}
int main() {int vexnum; int edge;cout << "输入图的种类:1代表有向图,2代表无向图" << endl;int kind;cin >> kind;//判读输入的kind是否合法while (1) {if (kind == 1 || kind == 2) {break;}else {cout << "输入的图的种类编号不合法,请重新输入:1代表有向图,2代表无向图" << endl;cin >> kind;}}cout << "输入图的顶点个数和边的条数:" << endl;cin >> vexnum >> edge;while (!check(vexnum, edge)) {cout << "输入的数值不合法,请重新输入" << endl;cin >> vexnum >> edge;}Graph_DG graph(vexnum, edge);graph.createGraph(kind);graph.print();graph.Floyd();graph.print_path();system("pause");return 0;
}

输入:

2
7 12
1 2 12
1 6 16
1 7 14
2 3 10
2 6 7
3 4 3
3 5 5
3 6 6
4 5 4
5 6 2
5 7 8
6 7 9 

输出:

最短路径问题---Floyd算法详解相关推荐

  1. 【最短路径Floyd算法详解推导过程】看完这篇,你还能不懂Floyd算法?还不会?...

    简介 Floyd-Warshall算法(Floyd-Warshall algorithm),是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似.该算法名称以 ...

  2. “chaos”的算法--之Floyd算法详解(求最短路径)

    倘若我们要在计算机上建立一个交通咨询系统则可以采用图的结构来表示实际的交通网络.其实现最基本的功能,求出任意两点间的最短路径, 求最短路径的经典方法有很多种,最常用的便是迪杰斯特拉算法和佛洛依德(Fl ...

  3. C++数据结构——旅游规划(Floyd算法详解)

    旅游规划 作者 陈越 单位 浙江大学 有了一张自驾旅游路线图,你会知道城市间的高速公路长度.以及该公路要收取的过路费.现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径.如果有 ...

  4. 弗洛伊德(Floyd)算法详解

    Floyd 算法是解决图论问题的比较经典的算法,用来求解赋权图中每对顶点间的最短距离.当然,在求距离的过程中也可以得到最短距离的路径.这个算法与迪杰斯特拉(Dijkstra)算法相似,他们两个都属于最 ...

  5. Dijkstra算法和Floyd算法详解(MATLAB代码)

    一.Dijkstra算法 1.算法简介 Dijkstra算法是由E.W.Dijkstra于1959年提出,又叫迪杰斯特拉算法,它应用了贪心算法模式,是目前公认的最好的求解最短路径的方法.算法解决的是有 ...

  6. 最短路径问题---Dijkstra算法详解

    前言 Nobody can go back and start a new beginning,but anyone can start today and make a new ending. Na ...

  7. dijkstra 算法_最短路径问题Dijkstra算法详解

    1.Dijkstra算法介绍 · 算法起源: · Djkstra 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法,由计算机科学家E ...

  8. 最短路径问题 --- Dijkstra算法详解

    最短路径问题 最短路径问题 1.最短路径问题介绍 2.Dijkstra 算法思路 3.Dijkstra算法示例演示 4.Dijkstra算法的代码实现(c++) 参考 最短路径问题 1.最短路径问题介 ...

  9. 最短路dijkstra算法详解_最短路径问题---Dijkstra算法详解

    1.Dijkstra算法介绍 · 算法起源: · Djkstra 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法,由计算机科学家E ...

最新文章

  1. 计算机软件打开为什么跑一边,为什么打开Excel后开始菜单就跑掉了?
  2. 11.系统安全分析与设计
  3. Cannot change version of project facet Dynamic Web Module to 2.5 问题的解决方法
  4. 会员系统整合的想法[择]
  5. sort--排序函数
  6. Android Service介绍
  7. android签名文件查看工具,ionic 发布android,并查看签名文件。
  8. 胎压监测 (15 分)
  9. 计算机网络误区——源目IP和源目MAC变化问题
  10. 传智播客扫地僧C/C++学习 数据类型的本质
  11. librdkafka安装步骤
  12. 华为交换机常用查询命令
  13. Mac如何破解管理员密码
  14. 设计模式--适配器模式
  15. vim使用自定义snippets
  16. 0基础学习前端开发,高职web前端开发技能大赛
  17. html/css笔记 文本添加下划线方法
  18. 微商靠什么引流?微商有哪些平台可以精准引流?
  19. 面向对象的五大基本原则(SOLID)
  20. php cakephp like,cakephp常见知识点汇总

热门文章

  1. 快速实现软件试用的解决方案
  2. 剪切图片的某个部分(2)
  3. 《足球智商》读书笔记
  4. linux篇【3】:Linux 环境基础开发工具yum,vim,gcc,makefile,git
  5. Android 加载本地图片(文件管理器中的图片墙)
  6. [附源码]计算机毕业设计springboot海滨学院学生大创项目申报与审批系统
  7. 计算机音乐桃源恋歌,谁有桃源恋歌的谱子
  8. RabbitMq初识(一)
  9. 具有大写字母和数字的随机字符串生成
  10. postgresql逻辑备份工具pg_dump和pg_resotre学习