最短路问题(short-path problem):最短路问题是图论研究中的一个经典算法问题,指在寻找图(由结点和路径组成的)中两结点之间的最短路径。算法具体的形式包括:

1.确定起点的最短路径问题 - 即已知起始结点,求最短路径的问题。

2.确定终点的最短路径问题 - 与确定起点的问题相反,该问题是已知终结结点,求最短路径的问题。在无向图中该问题与确定起点的问题完全等同,在有向图中该问题 等同于把所有路径方向反转的确定起点的问题。

3.确定起点终点的最短路径问题 - 即已知起点和终点,求两结点之间的最短路径。

4.全局最短路径问题 - 求图中所有的最短路径。


以一个故事开头吧:

这又是晴朗的一天,XF准备去旅行,但他这次想去看自由男神像。所以他正在用千度查一查机票的价格:

出发地			目的地      		单价
夫代尔马 自由男神像 15000 yuan
浮卢宫 尼悉歌剧院 100 yuan
尼悉歌剧院 自由男神像 1000 yuan
夫代尔马 浮卢宫 10 yuan

XF现在住在夫代尔马,他发现直接由夫代尔马去自由男神像会比夫代尔马->浮卢宫->尼悉歌剧院->自由男神像花费的钱多一些,~~或者说,多得多。。。~~所以他决定选择
夫代尔马->浮卢宫->尼悉歌剧院->自由男神像这一条便宜的方案!!!


故事结束!

那么,我们把XF的机票选择方案扩大很多很多倍,且让XF住的地方变来变去,就成为了求一个多源最短路径的题啦!!
那么对于这类问题,我们应该砸么做类??

Floyd算法隆重出场!!!

首先,我要问一个问题:为什么两个顶点的最短距离为什么不是它们的直接距离呢???
局外读者:“因为他们有可能没有直接连接的边,而是由一个或多个中继顶点间接连接的啊!!!”
对啦!真聪明!!!
举个栗子:

上图的顶点A和顶点C没有直接相连的边,它们之间没有直接距离。
如果以B作为“中继顶点”,此时A到C的最短路径就是A-B-C,最短距离是3+2=5
那么,再举个栗子:
上图的顶点A和顶点C直接相连,距离是6。但是存在一条“迂回”路径A-B-C,距离是3+2=5<6。
所以,经过中继顶点B,从A到C的最短距离是5。
这就是弗洛伊德算法的核心思想,我们利用这些中继顶点,一步一步推导出图中所有顶点的最短距离;
下面我们来看一看Floyd算法的详细步骤。

  1. 要实现Floyd算法,首先需要构建带权图的邻接矩阵:

    在邻接矩阵当中,每一个数字代表着从某个顶点到另一个顶点的直接距离,这个距离是没有涉及到任何中继顶点的。
  2. 此时假定只允许以顶点A作为中继顶点,那么各顶点之间的距离会变成什么样子呢?
    B和C之间的距离原本是无穷大,此时以A为中继,距离缩短为AB距离+AC距离=
    5+2=7。
    更新对应矩阵元素(橙色区域代表顶点A到其他顶点的临时距离:
  3. 接下来以顶点A、B作为中继顶点,那么各顶点之间的距离会变成什么样子呢?
    A和D之间的距离原本是无穷大,此时以B为中继,距离缩短为AB距离+BD距离=5+1=6。
    A和E之间的距离原本是无穷大,此时以B为中继,距离缩短为AB距离+BE距离=5+6=11。
    更新对应矩阵元素(橙色区域代表顶点B到其他顶点的临时距离):
  4. 接下来以顶点A、B、C作为中继顶点,那么各顶点之间的距离会变成什么样子呢?
    A和F之间的距离原本是无穷大,此时以C为中继,距离缩短为AC距离+CF距离=2+8=10。
    更新对应矩阵元素(橙色区域代表顶点C到其他顶点的临时距离):
    以此类推,我们不断引入新的中继顶点,不断刷新矩阵中的临时距离。
    最终,当所有顶点都可以作为中继顶点时,我们的距离矩阵更新如下:


此时,矩阵中每一个元素,都对应着某顶点到另一个顶点的最短距离。
让我们回顾一下动态规划的两大要素:

问题的初始状态
问题的状态转移方程式

对于寻找图的所有顶点之间距离的问题,初始状态就是顶点之间的直接距离,也就是邻接矩阵。
而问题的状态转移方程式又是什么呢?
假设新引入的中继顶点是n,那么:
顶点i 到 顶点j 的新距离 = Min(顶点i 到 顶点j 的旧距离,顶点i 到 顶点n 的距离+顶点n 到 顶点j 的距离
所以:

弗洛伊德是一种基于动态规划的多源点最短路算法!


回到故事,如果XF就一直住在夫代尔马呢??
那么,这就转换为一道单源最短路径问题了。。。

Dijkstra算法隆重出场!!!

究竟什么是迪杰斯特拉算法?它是如何寻找图中顶点的最短路径呢?
这个算法的本质,是不断刷新起点与其他各个顶点之间的 “距离表”
让我们来演示一下迪杰斯特拉的详细过程:

  1. ,创建距离表。表中的Key是顶点名称,Value是从起点A到对应顶点的已知最短距离。但是,一开始我们并不知道A到其他顶点的最短距离是多少,Value默认是无限大

  2. ,遍历起点A,找到起点A的邻接顶点B和C。从A到B的距离是5,从A到C的距离是2。把这一信息刷新到距离表当中:

  3. ,从距离表中找到从A出发距离最短的点,也就是顶点C。

  4. ,遍历顶点C,找到顶点C的邻接顶点D和F(A已经遍历过,不需要考虑)。从C到D的距离是6,所以A到D的距离是2+6=8;从C到F的距离是8,所以从A到F的距离是2+8=10。把这一信息刷新到表中:
    接下来重复第3步、第4步所做的操作:

  5. ,也就是第3步的重复,从距离表中找到从A出发距离最短的点(C已经遍历过,不需要考虑),也就是顶点B。

  6. ,也就是第4步的重复,遍历顶点B,找到顶点B的邻接顶点D和E(A已经遍历过,不需要考虑)。从B到D的距离是1,所以A到D的距离是5+1=6,小于距离表中的8;从B到E的距离是6,所以从A到E的距离是5+6=11。把这一信息刷新到表中:(在第6步,A到D的距离从8刷新到6,可以看出距离表所发挥的作用。距离表通过迭代刷新,用新路径长度取代旧路径长度,最终可以得到从起点到其他顶点的最短距离)

  7. ,从距离表中找到从A出发距离最短的点(B和C不用考虑),也就是顶点D。

  8. ,遍历顶点D,找到顶点D的邻接顶点E和F。从D到E的距离是1,所以A到E的距离是6+1=7,小于距离表中的11;从D到F的距离是2,所以从A到F的距离是6+2=8,小于距离表中的10。把这一信息刷新到表中:
    (过了一百年——————)

    就这样,除终点以外的全部顶点都已经遍历完毕,距离表中存储的是从起点A到所有顶点的最短距离。显然,从A到G的最短距离是11。(路径:A-B-D-F-G)

弗洛伊德代码实现:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std; int n,m,x,y;
long long dp[505][505];
int pre[505][505]; void HH(int z){
if(pre[x][z]==0)
return ;
HH(pre[x][z]);
printf("%d ",z);
} int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
dp[i][j]=214748360;
}
for(int i=1;i<=m;i++){
int sum;
cin>>x>>y>>sum;
dp[x][y]=sum;
pre[x][y]=x;
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(dp[i][j]>dp[i][k]+dp[k][j]){
dp[i][j]=dp[i][k]+dp[k][j];
pre[i][j]=pre[k][j];
}
}
}
}
cin>>x>>y;
cout<<dp[x][y]<<endl;
printf("%d ",x);
HH(y);
return 0;
}

Dijkstra算法:

#include<bits/stdc++.h>
using namespace std;
int n,m,x,y;
bool flag[5005]={};
int dp[5005][5005],f[5005];
int main(){
cin>>n>>m>>x>>y;
memset(dp,0x3f,sizeof(dp));
memset(f,0x3f,sizeof(f));
for(int i=1;i<=m;i++){
int xx,yy,zz;
scanf("%d %d %d",&xx,&yy,&zz);
dp[xx][yy]=dp[yy][xx]=zz;
}
f[x]=0;
flag[x]=0;
for(int i=1;i<=n;i++){
int Minn=0x3f3f3f3f;
int k=0;
for(int j=1;j<=n;j++){
if(flag[j]==0&&(f[j]<Minn)){
Minn=f[j];
k=j;
}
}
if(k==0) continue;
flag[k]=1;
for(int j=1;j<=n;j++){
if(f[j]>f[k]+dp[k][j]){
f[j]=f[k]+dp[k][j];
}
}
}
printf("%d",f[y]);
return 0;
}

xf浅谈_最短路的更多相关文章

  1. 浅谈_依赖注入 asp.net core

    1.1什么是依赖 我们先看下图 可以简单理解,一个HomeController类使用到了DBContext类,而这种关系是有偶然性,临时性,弱关系的,但是DBContext的变化会影响到HomeCon ...

  2. 安卓开发_浅谈ListView(SimpleAdapter数组适配器)

    安卓开发_浅谈ListView(ArrayAdapter数组适配器) 学习使用ListView组件和SimapleAdapter适配器实现一个带图标的ListView列表 总共3部分 一.MainAc ...

  3. 安卓开发_浅谈Android动画(四)

    Property动画 概念:属性动画,即通过改变对象属性的动画. 特点:属性动画真正改变了一个UI控件,包括其事件触发焦点的位置 一.重要的动画类及属性值: 1.  ValueAnimator 基本属 ...

  4. 安卓开发_浅谈ListView(自定义适配器)

    ListView作为一个实际开发中使用率非常高的视图,一般的系统自带的适配器都无法满足开发中的需求,这时候就需要开发人员来自定义适配器使得ListView能够有一个不错的显示效果 有这样一个Demo ...

  5. 浅谈android代码保护技术_ 加固

    浅谈android代码保护技术_加固 导语 我们知道Android中的反编译工作越来越让人操作熟练,我们辛苦的开发出一个apk,结果被人反编译了,那心情真心不舒服.虽然我们混淆,做到native层,但 ...

  6. python进阶_浅谈面向对象进阶

    python进阶_浅谈面向对象进阶 学了面向对象三大特性继承,多态,封装.今天我们看看面向对象的一些进阶内容,反射和一些类的内置函数. 一.isinstance和issubclass  class F ...

  7. 转【】浅谈sql中的in与not in,exists与not exists的区别_

    浅谈sql中的in与not in,exists与not exists的区别   1.in和exists in是把外表和内表作hash连接,而exists是对外表作loop循环,每次loop循环再对内表 ...

  8. 多测师浅谈 学员实现价值就是我们的幸福_高级讲师肖sir

    学员实现价值就是我们的幸福 作为一名资深的IT高级讲师,在传统的行业IT薪资基本都是过万,作为一名IT培训教师,培养出在不同领域的测试,并且接触各种各样的产品,目前市场流行的比如银行业务系统,语音类系 ...

  9. 浅谈SQL注入风险 - 一个Login拿下Server

    前两天,带着学生们学习了简单的ASP.NET MVC,通过ADO.NET方式连接数据库,实现增删改查. 可能有一部分学生提前预习过,在我写登录SQL的时候,他们鄙视我说:“老师你这SQL有注入,随便都 ...

随机推荐

  1. [刷题] 144 Binary Tree Preorder Traversal

    要求 二叉树的前序遍历 实现 递归 栈模拟          定义结构体 Command 模拟指令,字符串s描述命令,树节点node为指令作用的节点 定义栈 Stack 存储命令 1 #include ...

  2. [Windows] 屏幕截图 - FastStone Capture(FSCapture) v9.4 飞扬时空汉化绿色版(官方地址) 【清晰好用 已验证】

    [Windows] 屏幕截图 - FastStone Capture(FSCapture) v9.4 飞扬时空汉化绿色版(官方地址) [复制链接]     愤怒の葡萄 电梯直达 楼主    发表于 2 ...

  3. canal 实现Mysql到Elasticsearch实时增量同步

    简介: MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品.MySQL是一种关系数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据 ...

  4. 本文介绍使用windows系统自带的远程桌面mstsc连接Centos 7.x远程桌面的基本方法。

    本文介绍使用windows系统自带的远程桌面mstsc连接Centos 7.x远程桌面的基本方法. 一.前言 我希望用windows远程访问centos图形界面.xmanager连接centos远程桌 ...

  5. java和kotlin的可见性修饰符对比

    private 意味着只在这个类内部(包含其所有成员)可见: protected-- 和 private一样 + 在子类中可见. internal -- 能见到类声明的 本模块内 的任何客户端都可见其 ...

  6. Google Hacking 搜索引擎攻击与防范

    Google Hacking,有时也会被称为 Google dorking,是一种利用谷歌搜索的高级使用方式进行信息收集的技术.这个概念最早在2000年由黑客 Johnny Long 提出并推广,一系 ...

  7. Navicat Premium 15 linux 安装与激活 ArchLinux 2021

    查看了很多教程花了半小时才弄好可真不容易 参考https://github.com/orginly/navicat-keygen 下载地址 http://www.navicat.com.cn/down ...

  8. [leetcode] 116. 填充同一层的兄弟节点

    116. 填充同一层的兄弟节点 其实就是个二叉树的层次遍历 class Solution { public void connect(TreeLinkNode root) { if (root == ...

  9. Vue&Element 前端应用开发之菜单和路由的关系

    我们一般的应用系统,菜单是很多功能界面的入口,菜单为了更好体现功能点的设置,一般都是动态从数据库生成的,而且还需要根据用户角色的不同,过滤掉部分没有权限的菜单:在Vue&Element的纯前端 ...

  10. 台积电5nm光刻技术

    台积电5nm光刻技术 在IEEE IEDM会议上,台积电发表了一篇论文,概述了其5nm工艺的初步成果.对于目前使用N7或N7P工艺的客户来说,下一步将会采用此工艺,因为这两种工艺共享了一些设计规则.新 ...