最短路问题(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. [c++] 分号的使用

    加分号的情况: 语句结束加分号(否则编译器不知道在哪里结束语句,编译器不识别换行,写代码时换行和退格只是为了看着舒服,但本质上代码是写给编译器看的) 声明语句后加分号(也是一种语句) 结构体.类定义后 ...

  2. javaWeb——Servlet(二)

    Servelet登录页面步骤: 浏览器访问http://127.0.0.1/login.html 浏览器通过form把账号和密码提交到/login(通过action),附带method="p ...

  3. CentOS 7 调整home大小

    把/home内容备份,然后将/home文件系统所在的逻辑卷删除,扩大/root文件系统,新建/home: tar cvf /tmp/home.tar /home #备份/home umount /ho ...

  4. 使用LUKS加密你的磁盘

    计算机数据的安全,保密性在现在的生活中显得越来越重要.随着数字化的时代的来临,越来越多的数据被数字化,特别是更多有关于我们隐私的数据在不断生成,甚至还有我们需要离线保存的密钥等.而且通常我们使用磁盘, ...

  5. reboot 就是 poweroff 然后power on

    halt Shut down and halt the system poweroff Shut down and power-off the system reboot [ARG] Shut dow ...

  6. Scala 字符串插值器

    Scala 提供了三种创新的字符串插值方法:s,f和raw,使用他们我们可以方便快捷的组合字符串. s 字符串插值器 在任何字符串前加上s,就可以直接在串中使用变量了,在生成字符串的时候会隐式调用其t ...

  7. mysql基础之日志管理(查询日志、慢查询日志、错误日志、二进制日志、中继日志、事务日志)

    日志文件记录了MySQL数据库的各种类型的活动,MySQL数据库中常见的日志文件有 查询日志,慢查询日志,错误日志,二进制日志,中继日志 ,事务日志. 修改配置或者想要使配置永久生效需将内容写入配置文 ...

  8. 10.5 arp:管理系统的arp缓存

    arp命令 用于操作本机的arp缓存区,它可以显示arp缓存区中的所有条目.删除指定的条目或者添加静态的IP地址与MAC地址的对应关系.     什么是arp?即地址解析协议(ARP,Address ...

  9. 灵动微电子ARM Cortex M0 MM32F0010 UART1和UART2中断接收数据

    灵动微电子ARM Cortex M0 MM32F0010 UART1和UART2中断接收数据 目录: 1.MM32F0010UART简介 2.MM32F0010UART特性 3.MM32F0010使用 ...

  10. [Distributed ML] Parameter Server & Ring All-Reduce

    Resource ParameterServer入门和理解[较为详细,涉及到另一个框架:ps-lite] 一文读懂「Parameter Server」的分布式机器学习训练原理 并行计算与机器学习[很有 ...