最短路径(Floyd算法)
声明:图片及内容基于https://www.bilibili.com/video/BV1oa4y1e7Qt?from=articleDetail
多源最短路径的引入

Floyd算法
原理



加入a:

加入b:

加入c:

数据结构


核心代码
Floyd()
void MGraph::Floyd(){
for(int i=0;i<vertexNum;i++){
for(int j=0;j<vertexNum;j++){
dist[i][j]=arc[i][j]; //dist数组初始化
if(dist[i][j]!=INFINIT&&dist[i][j]!=0) //dist为INFINIT则无路径,dist为0则指向自己
path[i][j]=vertex[i]+vertex[j]; //path数组初始化
else
path[i][j]=""; //不符合则path为空串
}
}
for(int k=0;k<vertexNum;k++){ //k个顶点循环k次
for(int i=0;i<vertexNum;i++){ //k每循环一次,要更新dist和path数组
for(int j=0;j<vertexNum;j++){
if(dist[i][k]+dist[k][j]<dist[i][j]){
dist[i][j]=dist[i][k]+dist[k][j];
//这里两个path拼接的时候,第一个字符串的最后一个字符和第二个字符串的第一个字符重复
//用substr去除第一个字符串的最后一个字符
string tmp=path[i][k].substr(0,path[i][k].length()-1);
path[i][j]=tmp+path[k][j];
}
}
}
}
displayDist();
displayPath();
}
完整代码
#include<iostream>
#define MAX 50
#define INFINIT 65535
#include <string>
using namespace std;
class MGraph{
private:
int vertexNum,arcNum; //顶点数,边数
int arc[MAX][MAX]; //邻接矩阵
string vertex[MAX]; //顶点信息
int dist[MAX][MAX];
string path[MAX][MAX];
public:
MGraph(string v[],int n,int e);
void display();
void Floyd();
void displayDist();
void displayPath();
};
void MGraph::Floyd(){
for(int i=0;i<vertexNum;i++){
for(int j=0;j<vertexNum;j++){
dist[i][j]=arc[i][j]; //dist数组初始化
if(dist[i][j]!=INFINIT&&dist[i][j]!=0) //dist为INFINIT则无路径,dist为0则指向自己
path[i][j]=vertex[i]+vertex[j]; //path数组初始化
else
path[i][j]=""; //不符合则path为空串
}
}
for(int k=0;k<vertexNum;k++){ //k个顶点循环k次
for(int i=0;i<vertexNum;i++){ //k每循环一次,要更新dist和path数组
for(int j=0;j<vertexNum;j++){
if(dist[i][k]+dist[k][j]<dist[i][j]){
dist[i][j]=dist[i][k]+dist[k][j];
//这里两个path拼接的时候,第一个字符串的最后一个字符和第二个字符串的第一个字符重复
//用substr去除第一个字符串的最后一个字符
string tmp=path[i][k].substr(0,path[i][k].length()-1);
path[i][j]=tmp+path[k][j];
}
}
}
}
displayDist();
displayPath();
}
void MGraph::displayDist(){ //打印dist数组
cout<<"dist数组:"<<endl;
for(int i=0;i<vertexNum;i++){
for(int j=0;j<vertexNum;j++){
cout<<dist[i][j]<<"\t";
}
cout<<endl;
}
}
void MGraph::displayPath(){ //打印path数组
cout<<"path数组:" <<endl;
for(int i=0;i<vertexNum;i++){
for(int j=0;j<vertexNum;j++){
cout<<path[i][j]<<"\t";
}
cout<<endl;
}
}
MGraph::MGraph(string v[],int n,int e){ //n是顶点数,e是边数
vertexNum=n;
arcNum=e;
for(int i=0;i<vertexNum;i++){
vertex[i]=v[i];
}
for(int i=0;i<arcNum;i++){ //初始化邻接矩阵
for(int j=0;j<arcNum;j++){
if(i==j) arc[i][j]=0;
else arc[i][j]=INFINIT;
}
}
int vi,vj,w;
for(int i=0;i<arcNum;i++){
cout<<"请输入有向边的两个顶点和这条边的权值"<<endl;
cin>>vi>>vj>>w; //输入边依附的两个顶点的编号 和权值
arc[vi][vj]=w; //有边标志
}
}
void MGraph::display(){
cout<<"邻接矩阵:"<<endl;
for(int i=0;i<vertexNum;i++){
for(int j=0;j<vertexNum;j++){
if(arc[i][j]==INFINIT)
cout<<"∞"<<"\t";
else cout<<arc[i][j]<<"\t";
}
cout<<endl;
}
cout<<endl;
cout<<"结点信息:"<<endl;
for(int i=0;i<vertexNum;i++){
cout<<vertex[i]<<" ";
}
cout<<endl;
}
int main(){
int n,e;
string v[MAX];
cout<<"请输入顶点数和边数"<<endl;
cin>>n>>e;
cout<<"请输入顶点信息"<<endl;
for(int i=0;i<n;i++){
cin>>v[i];
}
MGraph mgraph(v,n,e);
mgraph.display();
mgraph.Floyd();
return 0;
}
输入:
3 5
a b c
0 1 4
0 2 11
1 0 6
1 2 2
2 0 3
输出:
邻接矩阵:
0 4 11
6 0 2
3 ∞ 0
结点信息:
a b c
dist数组:
0 4 6
5 0 2
3 7 0
path数组:
ab abc
bca bc
ca cab

例题:娱乐中心选址


#include<iostream>
#define MAX 50
#define INFINIT 65535
#include <string>
using namespace std;
class MGraph{
private:
int vertexNum,arcNum; //顶点数,边数
int arc[MAX][MAX]; //邻接矩阵
string vertex[MAX]; //顶点信息
int dist[MAX][MAX];
string path[MAX][MAX];
int rowSum[MAX];
int rowMax[MAX];
public:
MGraph(string v[],int n,int e);
void display();
void Floyd();
void displayDist();
void displayPath();
void bestCentralAmusement();
void displayRowMax();
void displayRowSum();
};
void MGraph::bestCentralAmusement(){
for(int i=0;i<vertexNum;i++)
rowSum[i]=0;
for(int i=0;i<vertexNum;i++){
for(int j=0;j<vertexNum;j++){
rowSum[i]+=dist[i][j];
}
}
int tmp;
for(int i=0;i<vertexNum;i++){
tmp=0;
for(int j=0;j<vertexNum;j++){
if(tmp<dist[i][j]) tmp=dist[i][j];
}
rowMax[i]=tmp;
}
int tmp2=INFINIT;
int index=-1;
for(int i=0;i<vertexNum;i++){
if(rowMax[i]<tmp2){
tmp2=rowMax[i];
index=i;
}
if(tmp2==rowMax[i]){
if(rowSum[i]<tmp2){
index=i;
}else{
;
}
}
}
displayRowMax();
displayRowSum();
cout<<"index:"<<index<<endl;
cout<<"最合适的位置是"<<vertex[index]<<endl;
}
void MGraph::displayRowSum(){
cout<<"rowSum: "<<endl;
for(int i=0;i<vertexNum;i++)
cout<<rowSum[i]<<" ";
cout<<endl;
}
void MGraph::displayRowMax(){
cout<<"rowMax:"<<endl;
for(int j=0;j<vertexNum;j++)
cout<<rowMax[j]<<" ";
cout<<endl;
}
void MGraph::Floyd(){
for(int i=0;i<vertexNum;i++){
for(int j=0;j<vertexNum;j++){
dist[i][j]=arc[i][j]; //dist数组初始化
if(dist[i][j]!=INFINIT&&dist[i][j]!=0) //dist为INFINIT则无路径,dist为0则指向自己
path[i][j]=vertex[i]+vertex[j]; //path数组初始化
else
path[i][j]=""; //不符合则path为空串
}
}
for(int k=0;k<vertexNum;k++){ //k个顶点循环k次
for(int i=0;i<vertexNum;i++){ //k每循环一次,要更新dist和path数组
for(int j=0;j<vertexNum;j++){
if(dist[i][k]+dist[k][j]<dist[i][j]){
dist[i][j]=dist[i][k]+dist[k][j];
//这里两个path拼接的时候,第一个字符串的最后一个字符和第二个字符串的第一个字符重复
//用substr去除第一个字符串的最后一个字符
string tmp=path[i][k].substr(0,path[i][k].length()-1);
path[i][j]=tmp+path[k][j];
}
}
}
}
displayDist();
displayPath();
}
void MGraph::displayDist(){ //打印dist数组
cout<<"dist数组:"<<endl;
for(int i=0;i<vertexNum;i++){
for(int j=0;j<vertexNum;j++){
cout<<dist[i][j]<<"\t";
}
cout<<endl;
}
}
void MGraph::displayPath(){ //打印path数组
cout<<"path数组:" <<endl;
for(int i=0;i<vertexNum;i++){
for(int j=0;j<vertexNum;j++){
cout<<path[i][j]<<"\t";
}
cout<<endl;
}
}
MGraph::MGraph(string v[],int n,int e){ //n是顶点数,e是边数
vertexNum=n;
arcNum=e;
for(int i=0;i<vertexNum;i++){
vertex[i]=v[i];
}
for(int i=0;i<arcNum;i++){ //初始化邻接矩阵
for(int j=0;j<arcNum;j++){
if(i==j) arc[i][j]=0;
else arc[i][j]=INFINIT;
}
}
int vi,vj,w;
for(int i=0;i<arcNum;i++){
cout<<"请输入有向边的两个顶点和这条边的权值"<<endl;
cin>>vi>>vj>>w; //输入边依附的两个顶点的编号 和权值
arc[vi][vj]=w; //有边标志
}
}
void MGraph::display(){
cout<<"邻接矩阵:"<<endl;
for(int i=0;i<vertexNum;i++){
for(int j=0;j<vertexNum;j++){
if(arc[i][j]==INFINIT)
cout<<"∞"<<"\t";
else cout<<arc[i][j]<<"\t";
}
cout<<endl;
}
cout<<endl;
cout<<"结点信息:"<<endl;
for(int i=0;i<vertexNum;i++){
cout<<vertex[i]<<" ";
}
cout<<endl;
}
int main(){
int n,e;
string v[MAX];
cout<<"请输入顶点数和边数"<<endl;
cin>>n>>e;
cout<<"请输入顶点信息"<<endl;
for(int i=0;i<n;i++){
cin>>v[i];
}
MGraph mgraph(v,n,e);
mgraph.display();
mgraph.Floyd();
mgraph.bestCentralAmusement();
return 0;
}
输入:
5 10
a b c d e
0 1 13
0 3 4
1 0 13
1 2 15
1 4 5
2 3 12
3 0 4
3 2 12
4 2 6
4 3 3
输出:
邻接矩阵:
0 13 ∞ 4 ∞
13 0 15 ∞ 5
∞ ∞ 0 12 ∞
4 ∞ 12 0 ∞
∞ ∞ 6 3 0
结点信息:
a b c d e
dist数组:
0 13 16 4 18
12 0 11 8 5
16 29 0 12 34
4 17 12 0 22
7 20 6 3 0
path数组:
ab adc ad abe
beda bec bed be
cda cdab cd cdabe
da dab dc dabe
eda edab ec ed
rowMax:
18 12 34 22 20
rowSum:
51 36 91 55 36
index:1
最合适的位置是b
最短路径(Floyd算法)的更多相关文章
- 单源最短路径Dijkstra算法,多源最短路径Floyd算法
1.单源最短路径 (1)无权图的单源最短路径 /*无权单源最短路径*/ void UnWeighted(LGraph Graph, Vertex S) { std::queue<Vertex&g ...
- 7-8 哈利·波特的考试(25 分)(图的最短路径Floyd算法)
7-8 哈利·波特的考试(25 分) 哈利·波特要考试了,他需要你的帮助.这门课学的是用魔咒将一种动物变成另一种动物的本事.例如将猫变成老鼠的魔咒是haha,将老鼠变成鱼的魔咒是hehe等等.反方向变 ...
- 最短路径(Floyd)算法
#include <stdio.h>#include <stdlib.h>/* Floyd算法 */#define VNUM 5#define MV 65536int P[VN ...
- 单源最短路径——Floyd算法
正如我们所知道的,Floyd算法用于求最短路径.Floyd算法可以说是Warshall算法的扩展,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3). Floyd算法的基本思想如下:从任意 ...
- 最短路径Floyd算法【图文详解】
Floyd算法 1.定义概览 Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被 ...
- 【最短路径Floyd算法详解推导过程】看完这篇,你还能不懂Floyd算法?还不会?
简介 Floyd-Warshall算法(Floyd-Warshall algorithm),是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似.该算法名称以 ...
- 图论之最短路径floyd算法
Floyd算法是图论中经典的多源最短路径算法,即求任意两点之间的最短路径. 它可采用动态规划思想,因为它满足最优子结构性质,即最短路径序列的子序列也是最短路径. 举例说明最优子结构性质,上图中1号到5 ...
- 最短路径—Floyd算法
Floyd算法 所有顶点对之间的最短路径问题是:对于给定的有向网络G=(V,E),要对G中任意两个顶点v,w(v不等于w),找出v到w的最短路径.当然我们可以n次执行DIJKSTRA算法,用FLOYD ...
- 最短路径——Floyd算法(含证明)
通过dij,ford,spfa等算法可以快速的得到单源点的最短路径,如果想要得到图中任意两点之间的最短路径,当然可以选择做n遍的dij或是ford,但还有一个思维量较小的选择,就是floyd算法. 多 ...
- 多源最短路径Floyd算法
多源最短路径是求图中任意两点间的最短路,采用动态规划算法,也称为Floyd算法.将顶点编号为0,1,2...n-1首先定义dis[i][j][k]为顶点 i 到 j 的最短路径,且这条路径只经过最大编 ...
随机推荐
- three.js all in one
three.js all in one https://www.npmjs.com/package/three # yarn add three # OR $ npm i three https:// ...
- 2021-02:Teams开发平台更新概述
作为2021年工作计划的一部分,我会在每月的第三个星期五发布Teams开发平台的更新报告,给大家整理和讲解最新的平台功能,以及特色场景.这是第一篇文章,我会挑选截至到2月份一些重要的更新,以后每月的更 ...
- Docker使用指南
上文简单介绍了docker,这边记录一下docker的使用. 一.Docker启停 1.启动docker systemctl start docker 2.关闭docker systemctl sto ...
- C#使用OpenCV剪切图形中的人物头像
前言 本文主要介绍如何使用OpenCV剪切图形中的人物头像. 准备工作 首先创建一个Wpf项目--OpenCV_Face_Wpf,这里版本使用Framework4.7.2. 然后使用Nuget搜索[E ...
- vscode好用插件总结
做个记录:https://blog.csdn.net/xishining/article/details/90819481 1.Auto Rename Tag --自动重命名成对的HTML标记.假如你 ...
- JSON的stringify和parse方法
一.JSON.parse() 方法用于将一个 JSON 字符串转换为对象. 以下代码为将字符串解析为对象,然后再赋值给对象 //页面初始化完成加载,option是传递的参数 onLoad: funct ...
- SpringBoot文件上传与POI的使用
1.使用springboot上传文件 本文所要源码在一个项目中,源码:https://github.com/zhongyushi-git/springboot-upload-download.git. ...
- 后端程序员之路 58、go wlog
daviddengcn/go-colortext: Change the color of console text.https://github.com/daviddengcn/go-colorte ...
- 后端程序员之路 35、Index搜索引擎实现分析4-最终的正排索引与倒排索引
# index_box 提供搜索功能的实现- 持有std::vector<ITEM> _buffer; 存储所有文章信息- 持有ForwardIndex _forward_index; ...
- Lua C++交互 应用实例步骤(UserData使用)
一.配置Lua C++交互环境 1.下载Lua 包环境 地址: https://www.lua.org/download.html ,我们这里用的是5.4.2版本. 2.新建C++ 控制台应用程序 3 ...