额,博主只是做了几(约数)道题而已,写这篇小结纯粹想留作纪念(勿喷,但是可以交流)(那啥,转载的话注明一下来源。。打字不容易。。)
最短路呢,包括三种算法,但是各有各的变种,其中变化有很多。
简单记录一下。
首先是三种算法:
1、Dijkstra算法。(单源点最短路径)
双手奉上啊哈雷算法。
然后开始叙述我所理解(如有雷同。。那就雷同吧)的:
有n个点,相互之间可能有所连接或者没有,那么现在,如果让求点1到点n之间的最短路,该怎么求?
这里面有个很有趣的东西,叫做松弛,翻译过来就是这么个意思:
假如已知最短路1-3长度为5,最短路1->4长度为7(无论是1-3,还是1-4均是当前最短,也可以理解成当前最优(dp)),而3->4的长度为1,那么这个时候,明显可以知道:1->3->4的长度是小于1->4的,那么现在把1-4更新到当前最优,长度也就是变成了6。
以上就是松弛操作。也就是假设在1-n中有一个x点,且用d数组表示1~其他点的当前最优最短路,用w二维数组表示两点之间的距离,那么给定一个当前最优点y,如果d[y]>d[x]+w[x][y],是不是说明d[y]可以有更小的值呢?答案显而易见。
那么这是一个点,题目中一共n个点,那么我用每一个点都去更新1到其他点的距离,那么全部更新过后,是不是d[n]表示的就是从1~n的最短路了呢?
而这一切,每一次更细都相当于在所有任意的两个点(其中一个点是1(起点))里插入第三个点,看是否能够松弛,若能,就松弛,不能,就不管了呗。
还有,既然,n个点都要去更新一遍,那么谁先去更新呢?
答案:当然是d值最小的那个点去更新,因为用最小的去更新,才可能更新的动呀。但是既然,只需要每个点更新一次,那么要做个标记,以防更新过的点再次进行更新。
d值会越来越小,那么初值肯定是越大越好咯。
但是呢,既然d数组代表的是1到其余各点的最短距离,那么d[1]肯定是0。。
例题博客(基本上我第一次写的题博客都很长。。):Til the Cows Come Home
来啊,代码伺候!!!

int INF=0x3f3f3f3f
for(int i=1;i<=n;i++)
{
    d[i]=INF;vis[i]=0;
}
d[1]=0;
for(int i=1;i<=n;i++)//每个点都要参与更新,所以循环n次
{int m=INF,x=-1;//m是为了找出最小那一个,x记录节点for(int j=1;j<=n;j++){if(!vis[j]&&d[j]<m){m=d[x=j];}}if(x!=-1){vis[x]=1;//用于更新过了,就要标记for(int j=1;j<=n;j++)//用最小的d[x]去更新d[j]{if(d[j]>d[x]+w[x][j])
            {                d[j]=d[x]+w[x][j];
            }
        }
    }
}

2、bellman(附加spfa)
既然已经知道什么是松弛(不知道的再看一遍,因为是环环相扣的),接下来就说一下什么是bellman。
刚才已经说了,Dijkstra算法是用n个点去更新从1点到其余各点(这里的1代表起点,谁是起点看题意,只需要把起点的d变成0就可以了)的最短路,那么也就是用的边去更新两点之间的距离。
然后就提出了bellman,思想是从源点逐次经过其他点,以缩短到达终点的距离,假设n个点不存在负权值回路,那么最多存在n-1条边,因为假设存在超过n-1条边,那么肯定会重复经过一个点,那么最短路就可以更新:
Bellman-Ford算法构造一个最短路径长度数组序列:dist(1)[u],dist(2)[u],dist(3)[u],…,dist(n-1)[u]。其中:
dist(1)[u]为从源点v0到终点u的只经过一条边的最短路径的长度,并有dist(1)[u]=edge[v0,u]。
dist(3)[u]为从源点v0出发最多经过不构成负权值回路的3条边到达终点u的最短路径长度。
……
dist(n-1)[u]为从源点v0出发最多经过不构成负权值回路的n-1条边到达终点u的最短路径长度。
算法的最终目的是计算出dist(n-1)[u],为源点v0到顶点u的最短路径长度,也就是利用n-1条边更新过后的最短距离。
采用递推方式计算dist(k)[u]。
设已经求出dist(k-1)[u],u=0,1,…,n-1,此即从源点v0最多经过不构成负权值回路的k-1条边到达终点u的最短路径的长度。
从图的邻接矩阵可以找出各个顶点j到达顶点u的(直接边)距离edge[j,u],计算min{distk-1[j]+edge[j,u]},可得从源点v0途经各个顶点,最多经过不构成回路的k条边到达终点u的最短路径的长度。 比较dist(k-1)[u]和min{dist(k-1)[j]+edge[j,u]},取较小者作为dist(k)[u]的值。
因此Bellman-Ford算法的递推公式(求源点v0到各顶点u的最短路径)为: 初始:dist(1)[u]=edge[v0,u],v0是源点 递推:dist(k)[u]=min{dist(k-1)[u],min{dist(k-1)[j]+edge[j,u]}} j=0,1,…,n-1,j<>u; k=2,3,4,…,n-1 。
所以,n-1次过后便可以得到最短路,如果n-1次后依旧可以更新,那么说明存在负权回路或者是正权回路。
其次,对于无论是Dijkstra还是Bellman,均有一个选点去更新的操作,那么有的时候,可能选出的点不能对任何点进行更新,所以造成了时间的浪费,而且,还有一句是被更新过的点一定可以去更新其他点(不知道对不对。。),然后呢,就会想到,为什么不把每次更新过的点装进一个容器呢?直到再没有点可以装进容器(代表最短路已是最优,更新完毕)。
然后想到了数组,想到了栈和队列,但是呢,数组模拟需要一数组还要一指针变量时刻维护,所以就用栈和队列吧,相同的时间复杂度,但是呢,还有一点,选出尽量小的去更新其他点,这样更好。所以,考虑优先队列,那为啥不考虑优先。。栈呢?因为意义一样呀。。。
回到正,负权的问题上,怎样进行初始化呢、、
对于负权,自然是越来越小,所以数组赋为极大值,正权的话,赋为0好了。
给出一篇判定负环的博客:Wormholes。
给出一篇判定正环的博客:Arbitrage,内含两种判定正环的方法,一个是bellman,一个是floyed(下文有)。
给出一篇使用spfa的题解(模板):Til the Cows Come Home。
然后,奉上优先队列(经典,当然不是我的。。)博客:优先队列详解。
以上就是bellman和spfa用法,对了,提到spfa就不得不提到差分约束系统,自行看下(尝试理解,因矩阵知识浅薄,所以只会最基础的):Candies,里面有差分约束的博客,但是最好还是先看下题,理解这种思想用于哪个方面。


3、floyed
floyed是求任意两点间的最短路算法,因为三个for让他拥有不小的局限性,若是1s的话,n的范围只能是100以下,若是bellman能够理解成为利用n-1条边去更新起点到定点的最短路,记录的是前i条边更新过后的状态,那么floyed就可以理解为利用点去更新,记录的是前i个点更新过后的当前最优状态,三个for,假如分别是k,i,j,那么每次都会利用k作为中间桥梁,询问,i->j,i->k->j这两个哪个更短。。。保留当前最优,直到利用所有点把这对i,j更新n遍。(也就是n遍Dijkstra),这样理解会不会容易一些。
然后呢,floyed会牵扯出一个问题,叫做传递闭包问题,也就是关系的一个转换而已,给出一道例题解析:Cow Contest,这种题数据小的话(<=100)直接floyed暴力过,大了的话,就又牵扯出一个概念,叫做强连通分量,又有三种算法(暂不解释)。


以上呢,就是三种算法,在这里,补充一点Dijkstra的变种,其实也不算是变种,只是松弛操作的内容有点区别而已,都是共通的。
其一呢:最小生成树之prim算法(补了一觉继续写。。)。
现在我不再区别最短路的三种算法,统称为最短路。
那么思考最短路与最小生成树的区别,一样是求的最小值,但是最短路两点之间的最短路,而最小生成树求得是将全图的点连起需要的最小长度。
给出百度百科解释(很容易理解):prim算法百度百科,每次都找已经找过的点的最小距离,那么利用代码怎么实现呢?
找到离部分连通图最近的d值的点,加入标记,然后用这条边去更新所有没有被标记的点的距离。
附代码:

void prim()
{for(int i=1;i<=n;i++)d[i]=w[1][i];//初始化,也可以全设为INFvis[1]=1;int sum=0;for(int i=2;i<=n;i++){int minn=INF,pos=0;for(int j=1;j<=n;j++)//选出一个最近的点{if(!vis[j]&&d[j]<minn){minn=d[pos=j];}}sum+=minn;//求最小距离vis[pos]=1;for(int j=1;j<=n;j++)//更新没有被标记的点if(!vis[j]&&d[j]>w[pos][j])d[j]=w[pos][j];}
}

d[j]>w[pos][j]是指:因为只要把全图连接起来便好,所以不用像最短路那样严格控制是一条路。并且,d数组的用法在变种里面都代表不同的含义,因为之前在写题解的时候写过了,所以直接给出那道题(内含d数组的讲解)Frogger,然后给出一道模板题:Jungle Roads。
其二呢,就是刚才给出的那道Frogger,这类题的基本题意是最一个有向或者无向图里,从一个起点(假设为st)到一个重点(假设为ed)有很多条路,那么,每一条路呢都有一个最大长度边和一个最小长度边,那么这类题就会拿这个做文章,问:从st到ed里所有路的最小边长的最大值是多少?或者是从st到ed里所有路的最大边长的最小值是多少?
而这些呢,主要就是d数组的差异,给出两道题,分别对应两种问法。
Frogger
Heavy Transportation。
那么整理到这里,也就是我花了那么多天的做的专题的成果了。
参考:floyed算法、bellman算法。
对了对了,再补充一个邻接表,双手奉上啊哈雷大大的邻接表博客,然后,就是自己的补充了:

假设一个有向图,存在n个点,m条边
那么:
我见过的有两种方式:
①
struct djh
{int u,v,w;代表含义分别是:左端点,右端点,边长
}edge[];这个数组的范围是按照m的范围而定的
int first[]这个数组的范围是按照n的范围而定的
int next[]这个数组的范围是按照m的范围而定的
初始化:
for(int i=1;i<=n;i++)
{first[i]=-1;
}
for(int i=1;i<=m;i++)
{next[i]=-1;
}
输入边的时候:
for(int i=1;i<=m;i++)
{scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);next[i]=first[edge[i].u];first[edge[i].u]=i;
}
dijs或者spfa或者其他引用的写法:
选出一个点;
res
for(int i=first[res];i!=-1;i=next[i])
{if(dis[edge[i].v>dis[edge[i].u]+edge[i].w){dis[edge[i].v=dis[edge[i].u]+edge[i].w}
}②
struct djh
{int to,w,next;分别代表右端点,边长,next数组
}edge[];这个数组的范围是按照m的范围而定的
int first[]这个数组的范围是按照n的范围而定的
初始化不变
输入边的时候:
tot=0;
while(m--)
{int u,v,w;scanf("%d%d%d",&u,&v,&w);edge[tot].nexx=first[u];edge[tot].v=v;edge[tot].w=w;first[u]=tot++;
}
dijs或者spfa或者其他引用的写法:
选出一个点;
res
for(int i=first[res];i!=-1;i=edge[i].nexx)
{if(d[edge[i].v]>d[res]+edge[i].w){d[edge[i].v]=d[res]+edge[i].w;}
}

以上便是个人用法。

最短路小结(三种算法+各种常见变种)相关推荐

  1. 爱因斯坦谜题解答(三种算法比较)

    爱因斯坦谜题:     在一条街上有颜色互不相同的五栋房子,不同国籍的人分别住在这五栋房子力,每人抽不同品牌的香烟,喝不同的饮料,养不同的宠物.已知如下情况: 1.  英国人住红色房子里. 2.  瑞 ...

  2. 绘制云图的三种算法(附C#代码)

    我们要做什么呢?就是输入一个二维数组, TestData = new double[9, 6] {{ 26,28,29,32,28,27},{ 27,30,32,35,30,28},{ 24,27,3 ...

  3. AES,RSA,IBE三种算法的比较

    文章目录 三种算法的概念解释 三种算法各自的优略 三种加密算法的对比 三种算法的应用场景 三种算法的概念解释 AES: 最为常见的一种对称加密算法,对称式加密就是加密和解密使用同一个密钥.信息接收双方 ...

  4. 三种算法求解经典N皇后问题

    三种算法求解经典N皇后问题 [问题描述] 八皇后问题是一个古老而著名的问题,是回溯算法的典型例题.该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击, ...

  5. js求两圆交点_详解js实现线段交点的三种算法

    本文讲的内容都很初级, 主要是面向和我一样的初学者, 所以请各位算法帝们轻拍啊 引用 已知线段1(a,b) 和线段2(c,d) ,其中a b c d为端点, 求线段交点p .(平行或共线视作不相交) ...

  6. 关于随机输出数组中所有元素的三种算法

    算法一:比较常见,也比较容易想到.缺点:如果arrA中有重复元素,那么重复的元素只会输出一次. int[] arrA={1,2,3,4,5,6}; int[] arrB=new int[arrA.le ...

  7. EL之DTRFGBT:基于三种算法(DT、RF、GBT)对泰坦尼克号乘客数据集进行二分类(是否获救)预测并对比各自性能

    EL之DT&RF&GBT:基于三种算法(DT.RF.GBT)对泰坦尼克号乘客数据集进行二分类(是否获救)预测并对比各自性能 目录 输出结果 ​设计思路 核心代码 输出结果 设计思路 核 ...

  8. java 求最大公因数_求最大公约数的三种算法(java实现)

    三种算法: //欧几里得算法(辗转相除): public static int gcd(int m,int n) { if(m int k=m; m=n; n=k; } //if(m%n!=0) { ...

  9. SQL Server 索引基础知识(10)----Join 时的三种算法简介

    我们书写查询语句的时候,Join 参数之前可以是下面三个 { LOOP | MERGE | HASH } JOIN  . 如果不使用,则系统自己分析那种方式快,使用那种方式. 这其实是SQL Serv ...

最新文章

  1. Linux内存中的 buffer 和 cache 到底是个什么东东?
  2. php mpdf html 转pdf,使用 MPDF 将HTML转为PDF,然后将该PDF转为PNG图片的时候,中文报错... ...汗血宝马...
  3. NPOI随笔——图片在单元格等比缩放且居中显示
  4. hive 临时表 with_Kettle(PDI)转换中输入表输入详解
  5. php 函数 打印,php打印函数入门教程
  6. 这个小姐姐真的很火辣......
  7. P3243 [HNOI2015]菜肴制作(拓扑排序、贪心)
  8. linux 查看下挂磁盘,linux下磁盘挂载与查看
  9. 使用对称加密来加密Spring Cloud Config配置文件
  10. OpenShift 4 之AMQ Streams(1) - 多个Consumer从Partition接收数据
  11. 直播间越播越没人,大部分刚开始做直播电商的人都会这样
  12. maven私服搭建:docker安装Sonatype Nexus以及寻找admin用户对应的随机初始密码
  13. 计算机终端保密检查系统使用教程,博智计算机终端保密检查系统
  14. 【职场新贵】告诉你如何在压力下高效工作
  15. 为Web登陆添加验证码功能
  16. 工业级POE交换机、企业级交换机、普通交换机之间各区别?
  17. win10共享文件夹“您没有权限访问,请与网络管理员联系请求访问权限”解决方案
  18. java多线程死锁代码_java多线程死锁 编写高质量代码:改善Java程序的151个建议...
  19. 区块链毕设开题技术路线
  20. 第7章 嵌入式uClinux及其应用开发(1)

热门文章

  1. 如何使用Stack Overflow ?
  2. EXCEL显示 文件未保存 解决方法
  3. Samba文件服务器的配置
  4. 基于全景相机的深度学习综述
  5. 数据库MySQL备份命令,手动备份MySQL数据库
  6. java 仿qq空间_仿QQ空间和微信朋友圈,高解耦高复用高灵活
  7. Elasticsearch 如何实现时间差查询?
  8. mosquitto 在 Windows 上的安装
  9. 关于出现IllegalArgumentException异常的可能原因
  10. 中兴二面(综合面试及口语测评)