约会怎么走到目的地最近呢?一文讲清所有最短路算法问题

这篇具有很好参考价值的文章主要介绍了约会怎么走到目的地最近呢?一文讲清所有最短路算法问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

      🚀🚀🚀🚀🚀订阅专栏👉 趣学算法(dog) 👈 带你学习算法原理 + 算法模板🚀🚀🚀🚀🚀
约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra

write in front

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra 朋友们好啊,好久没写过优质博客和算法博客了,所以今天打算把我最近学习的算法—最短路算法给大家讲一讲,我们将由浅入深地去讲解,以 “初学者” 的角度去探索式地学习。会一步步地推进讲解,而不是直接把枯燥的知识点倒出来,应该会有不错的阅读体验。如果觉得不错,可以 “一键三连” 支持一下博主!你们的关注就是我更新的最大动力!Thanks ♪ (・ω・)ノ


约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra七夕节那天,咱们的狗蛋约了豆花打算去万达广场约会看电影,为了彰显自己的绅士风度,狗蛋决定早点过去,于是他思考了一个问题:我该怎么走才能最快到达万达广场呢? 于是狗蛋打开了地图打算找到最短的路线,如下:
约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra
狗蛋发现了三条路都可以到达附近的万达广场,所以运用了自己小学时学的两点之间线段最短的知识 ,找到了2号路线,到了万达广场。

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra约会完成后的狗蛋在想,在计算机里面我们该如何找到去到万达广场最短的路呢? 在好奇心的驱使下,他找到了夏目学长来帮助他解决问题。

Ⅰ. Floyd 求最短路

0x00 算法介绍

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra夏目学长听到狗蛋的问题后 立刻给狗蛋说出了一个词 “Floyd算法” 然后说:先学习Floyd算法来打基础,进而解决你所面临的问题。

Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名。

简单的来说,算法的主要思想是动态规划(dp),而求最短路径需要不断松弛(看过《啊哈算法》的应该清楚什么是松弛)。 不过我不打算讲dp的解法,夏目学长觉得对于狗蛋来讲,会增加学习成本。

Floyd 属于多源最短路径算法能够求出任意2个顶点之间的最短路径,支持负权边
时间复杂度:O(N * N * N)

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra这里先给出算法模板,然后进行讲解。

✅ 模板:C++

1:for(int k=1;k<=n;k++)
2:        for(int i=1;i<=n;i++)
3:            for(int j=1;j<=n;j++)
4:                if(e[i][j]>e[i][k]+e[k][j])
5:                    e[i][j]=e[i][k]+e[k][j];

0x01 算法原理

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra夏目学长身为《啊哈算法》的粉丝就拿出了《啊哈算法》书上的算法例子了。

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra
上图中有4个城市8条公里,公路上的数字表示这条公路的长短,并且公里是单向的,现在夏目学长要求我们求出任意两个城市之间的最短路程,也就是求任意两个点之间的最短路经,这就是多源最短路问题

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra我们可以使用二维数组e (邻接矩阵) 来存储信息。比如1号城市到2号城市的路程为2,则e[1][2] = 2,2号城市无法到达4号城市,则设置为0x3f3f3f3f(最大值相当于正无穷大) ,城市自己到自己的距离为0,也就是e[1][1]=0 。

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra于是夏目学长让狗蛋思考如何让任意两点之间的距离变短?

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra当然是:只能引入第三个点k,通过k进行中转,也就是a->k->b,才能缩短路线a到b的路程

💬 eg1:
4号到3号,原本e[4][3]=12,通过1中转后,e[4][1]+e[1][3]=5+6=11,通过1和2号城市中转的话,e[4][1]+e[1][2]+e[2][3]=10,通过这个例子狗蛋明白了:每个顶点都有可能使得另外两个顶点之间的路程变短

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra夏目学长又说:假设我们只允许经过1号城市,求任意两城市之间的最短路程,应该如何求呢?

只需判断e[ i ][1]+e[1][ j ]是否比e[ i ][ j ]要小即可。

💬 eg2:
由于是任意两个城市之间的最短距离,所以 i 的范围是1 ~ n 同理 j 也是 1 ~ n

💬 代码演示:

for(int i=1;i<=n;++i)   //遍历起点城市
	for(int j=1;j<=n;++j) //遍历被缩小距离的城市
		if(e[i][j] > e[i][1]+e[1][j]) //如果我通过1城市进行中转后的距离比你现在直接到要近
			e[i][j]=e[i][1]+e[1][j];//则直接赋值给给e[i][j]即可

夏目学长又双叒叕说:假设我们允许经过1号城市和2号城市,求任意两点之间的最短路程,应该如何求呢?

我们需要在只允许经过 1号顶点时任意两点的最短路程的结果下,再判断如果经过2号顶点是否可以使得 i 号顶点到 j 号顶点之间的路程变得更短,即判断e[ i ][2]+e[2][ j ] 是否要比 e[ i ][ j ] 要小。

💬 代码演示:

//经过一号顶点
for(int i=1;i<=n;++i)//遍历起点城市
	for(int j=1;j<=n;++j)//遍历被缩小距离的城市
		if(e[i][j] > e[i][1]+e[1][j])//如果我通过1城市进行中转后的距离比你现在直接到要近
			e[i][j]=e[i][1]+e[1][j];//则直接赋值给给e[i][j]即可
			
//经过二号顶点
for(int i=1;i<=n;++i)//遍历起点城市
	for(int j=1;j<=n;++j)//遍历被缩小距离的城市
		if(e[i][j] > e[i][2]+e[2][j])//如果我通过2城市进行中转后的距离比你现在直接到要近
			e[i][j]=e[i][2]+e[2][j];//则直接赋值给给e[i][j]即可

因此以此类推:当我们允许通过所有顶点中转,我们可以轻松的写出我们前面写的算法模板。

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra这个时候狗蛋觉得自己行了,就让夏目学长给他出一个算法题…

0x02 算法应用

夏目学长拿到了AcWing算法基础课的一道模板题目给他:

854. Floyd求最短路

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra狗蛋看到后思索了一番便写出了代码:
💬 代码演示:

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 210, INF = 0x3f3f3f3f;
int n, m, Q;
int e[N][N];
void floyd()//我们讲的算法模板
{
    for (int k = 1; k <= n; k ++ )
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= n; j ++ )
                e[i][j] = min(e[i][j], e[i][k] + e[k][j]);
}
int main()
{
    scanf("%d%d%d", &n, &m, &Q);//输入
    for (int i = 1; i <= n; i ++ )//初始化
        for (int j = 1; j <= n; j ++ )
            if (i == j) e[i][j] = 0;
            else e[i][j] = INF;
    while (m -- )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);//建图
        e[a][b] = min(e[a][b], c);//建图
    }
    floyd();
    while (Q -- )
    {
        int a, b;
        scanf("%d%d", &a, &b);
        int t = e[a][b];//查询
        if (t > INF / 2) puts("impossible");
        else printf("%d\n", t);
    }
    return 0;
}

🚩 运行结果:
约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra
如果想进一步练习Floyd算法的话👉 Floyd算法+并查集算法专题训练👈详细看这篇博客所写的内容和题目,帮你迅速掌握这个算法

Ⅱ. Dijkstra 求最短路

0x00 算法介绍

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra当狗蛋学会了Floyd最短路算法之后,内心就开始蠢蠢欲动了,还没等到夏目学长开口,狗蛋就打算自己动手用Floyd算法去求自己到达万达广场的最短路,于是他像晚上打codeforces那样坐牢了起来,迟迟不见他敲代码,于是他突然想到夏目学长说过Floyd算法好像是求得多源最短路问题,而他实际遇到的是单源最短路问题,这时夏目学长才语重心长的说,不用着急,等你学会了Dijkstra算法后,自然就会啦

Dijkstra算法是典型的单源最短路径算法,基于贪心思想,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra简单来说就是:Dijkstra是一个基于贪心思想的单源最短路算法,从起点开始层层扩展,直到找到终点。

Dijkstra算法 属于单源最短路径算法能够求出起点到终点的最短路径,不支持负权边
时间复杂度:O(N * N)

这里先给出算法模板,然后进行讲解。

✅ 模板:C++

//解释dist数组含义
用一个 dist 数组保存源点到其余各个节点的距离,dist[i] 表示源点到节点 i 的距离。
初始时,dist 数组的各个元素为无穷大。
//解释st数组得含义
用一个状态数组 st 记录是否找到了源点到该节点的最短距离,st[i] 
如果为真,则表示找到了源点到节点 i 的最短距离,st[i] 
如果为假,则表示源点到节点 i 的最短距离还没有找到。
初始时,st 各个元素为假(falseint dijkstra()
{
    memset(dist,0x3f,sizeof dist);//初始化各个点距离为正无穷(0x3f3f3f3f)

    dist[1]=0;//起始为止设置成 0 

    for(int i=0;i<n;i++)//迭代 n 此
    {
        int t=-1;
        for(int j=1;j<=n;j++)
        {//遍历 dist 数组,找到没有确定最短路径的节点中距离源点最近的点t
            if(!st[j] && (t==-1 || dist[t] > dist[j]))
                t=j;
        }

        st[t]=true;//st[i] 置为 true。

        for(int j=1;j<=n;j++)//遍历 t 所有可以到达的节点 i
            dist[j]=min(dist[j],dist[t]+g[t][j]);//更新 dist[j]
    }
    if(dist[n]==0x3f3f3f3f) return -1;
    return dist[n];

}

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra估计在这里看到模板,你会和狗蛋一样,一下子就蒙了,不过没关系,下面夏目学长就开始讲解算法原理

0x01 算法原理

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra夏目学长就在黑板上画了一张这样得图,来帮助狗蛋理解Dijkstra算法原理。

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra

上图总共有五个城市,每个城市如果连线和箭头,则表示这两个城市可以从一个城市到达另一个城市,并且两者之间得距离也从图中标注了出来,现在夏目学长要求狗蛋去求起点1号城市到其余城市之间的最短距离,也就是求起点到任意点的最短路经,这就是单源最短路问题。

  1. 用一个 dist 数组保存源点到其余各个城市的距离,dist[i] 表示源点到城市 i 的距离
    初始时,dist 数组的各个元素为无穷大(0x3f3f3f3f)。

  2. 用一个状态数组 st 记录是否找到了源点到该节点的最短距离,st[i]
    如果为真,则表示找到了源点到城市 i 的最短距离,st[i]
    如果为假,则表示源点到城市 i 的最短距离还没有找到。
    初始时,st 各个元素为假(false)
    约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra

  3. 然后先把我们的起点初始化一下,也就是dist[1] = 0,接着我们找到1号城市可以到达的城市的最近的城市,显然我们举得例子是2号城市,
    约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra

  4. 遍历 dist 数组,找到一个节点,这个节点是:没有确定最短路径的节点中距离源点最近的点。假设该节点编号为 i。此时就找到了源点到该节点的最短距离,st[i] 置为 true。
    约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra

  5. 遍历 i 所有可以到达的节点 j,如果 dist[j] 大于 dist[i] 加上 i -> j 的距离,即 dist[j] > dist[i] + w[i][j](w[i][j] 为 i -> j 的距离) ,则更新 dist[j] = dist[i] + w[i][j]。
    约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra

  6. 重复 3 4 步骤,直到所有节点的状态都被置为 1。
    约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra

此时 dist 数组中,就保存了源点到其余各个节点的最短距离。

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra这个时候算法原理就讲解完毕了,勇敢狗蛋不怕困难,开始了算法实现,然后夏目学长问他,你知道为什么Dijkstra算法不能求负权边么? 狗蛋挠挠头说不知道,于是夏目学长就徐徐道来:
dijkstra不能解决负权边是因为 dijkstra要求每个点被确定后st[j] = truedist[j]就是最短距离了,之后就不能再被更新了 (一锤子买卖)而如果有负权边的话,那已经确定的点的dist[j]不一定是最短了

0x02 算法应用

在在狗蛋的哀求下夏目学长拿到了AcWing算法基础课的一道模板题目给他:
849. Dijkstra求最短路 I

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra狗蛋像是奖励自己一样,扑到电脑面前,写起了代码
💬 代码演示:

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;
const int N = 510;
int g[N][N];//邻接矩阵存储城市
bool st[N];//该点距离是否被确定了已经
int dist[N];//存储起点到终点的距离
int n,m;

int dijkstra()
{
    memset(dist,0x3f,sizeof dist);//初始化各个点距离为正无穷(0x3f3f3f3f)

    dist[1]=0;//起始为止设置成 0 

    for(int i=0;i<n;i++)//迭代 n 此
    {
        int t=-1;
        for(int j=1;j<=n;j++)
        {//遍历 dist 数组,找到没有确定最短路径的节点中距离源点最近的点t
            if(!st[j] && (t==-1 || dist[t] > dist[j]))
                t=j;
        }

        st[t]=true;//st[i] 置为 true。

        for(int j=1;j<=n;j++)//遍历 t 所有可以到达的节点 i
            dist[j]=min(dist[j],dist[t]+g[t][j]);//更新 dist[j]
    }
    if(dist[n]==0x3f3f3f3f) return -1;
    return dist[n];
}

int main()
{
    memset(g, 0x3f, sizeof g);
    cin>>n>>m;
    while(m--)
    {
        int a,b,w;
        cin>>a>>b>>w;//输入边和权重
        g[a][b]=min(g[a][b],w);//建图
    }
    
    int t=dijkstra();
    
    printf("%d\n",t);
    
    return 0;
}

🚩 运行结果:
约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra
约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra如果想进一步练习Dijkstra算法的话👉 最短路Dijkstra,spfa,图论二分图算法AYIT—ACM训练(模板版)👈详细看这篇博客所写的内容和题目,帮你迅速掌握这个算法

Ⅲ. bellman-ford 求最短路

0x01 算法介绍

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra当狗蛋以为自己能够挑战所有的最短路的题目的时候,突然遇到了一道有边数限制的最短路问题,于是他又屁颠屁颠的找到了夏目学长进行求教,这是不是很好的一种品质呢?不断学习,不断求教,不断进步!

于是夏目学长看到了算法题的题目如下:
约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra
约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra看完后夏目学长 哦~ 了一声,就跟狗蛋说,这是bellman-ford最短路算法,下面就来给你讲解一下这个算法:

Bellman - ford 算法是求含负权图的单源最短路径的一种算法,效率较低,代码难度较小。其原理为连续进行松弛,在每次松弛时把每条边都更新一下,若在 n-1 次松弛后还能更新,则说明图中有负环,因此无法得出结果,否则就完成。
( 通俗的来讲就是:假设 1 号点到 n 号点是可达的,每一个点同时向指向的方向出发,更新相邻的点的最短距离,通过循环 n-1 次操作,若图中不存在负环,则 1 号点一定会到达 n 号点,若图中存在负环,则在 n-1 次松弛后一定还会更新)

Bellman-ford算法 属于单源最短路径算法能够求出起点到终点的最短路径,支持负权边
时间复杂度:O(N * M)

这里先给出算法模板,然后进行讲解。

✅ 模板:C++

const int N = 510,M=10010;
int n,m,k;
int dist[N];//备份dist数组 //dist[N]表示从起点到当前点的当前最短距离
int backup[N];//备份dist数组 backup[j]表示每次进入第2重循环的dist数组的备份
struct Edge
{
    int a,b,w;
}e[M];

void bellman_ford()
{
    memset(dist,0x3f,sizeof dist);//初始化距离
    dist[1]=0;//起点设置为 0 
    for(int i=0;i<k;i++)//迭代K次
    {
        memcpy(backup,dist,sizeof dist);//备份dist数组的距离
        for(int j=0;j<m;j++)//迭代 m 次
        {
            int a=e[j].a,b=e[j].b,w=e[j].w;
            dist[b]=min(dist[b],backup[a]+w);//松弛操作
        }
    }
}

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra大家看到这里肯定和狗蛋一样一头雾水,下面就给大家讲解一下算法原理。♪ (・ω・)ノ

0x01 算法原理

for n次
 for 所有边 a,b,w (松弛操作)
  dist[b] = min(dist[b],backup[a] + w)

注意:backup[] 数组是上一次迭代后 dist[] 数组的备份,由于是每个点同时向外出发,因此需要对 dist[] 数组进行备份,若不进行备份会因此发生串联效应,影响到下一个点

在下面代码中,是否能到达n号点的判断中需要进行if(dist[n] > INF/2)判断,而并非是if(dist[n] == INF)判断,原因是INF是一个确定的值,并非真正的无穷大,会随着其他数值而受到影响,dist[n]大于某个与INF相同数量级的数即可

0x02 算法应用

AcWing 853. 有边数限制的最短路

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra狗蛋按照自己的理解,学出了代码。
💬 代码演示:

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = 510,M=10010;
int n,m,k;
int dist[N];//备份dist数组 //dist[N]表示从起点到当前点的当前最短距离
int backup[N];//备份dist数组 backup[j]表示每次进入第2重循环的dist数组的备份
struct Edge
{
    int a,b,w;
}e[M];

void bellman_ford()
{
    memset(dist,0x3f,sizeof dist);//初始化距离
    dist[1]=0;//起点设置为 0 
    for(int i=0;i<k;i++)//迭代K次
    {
        memcpy(backup,dist,sizeof dist);//备份dist数组的距离
        for(int j=0;j<m;j++)//迭代 m 次
        {
            int a=e[j].a,b=e[j].b,w=e[j].w;
            dist[b]=min(dist[b],backup[a]+w);//松弛操作
        }
    }
}

int main()
{
    cin>>n>>m>>k;
    for(int i=0;i<m;i++)
    {
        int a,b,w;
        cin>>a>>b>>w;
        e[i]={a,b,w};
    }
    bellman_ford();
    //在下面代码中,是否能到达n号点的判断中需要进行if(dist[n] > INF/2)判断,而并非是if(dist[n] == INF)判断,
    //原因是INF是一个确定的值,并非真正的无穷大,
    //会随着其他数值而受到影响,dist[n]大于某个与INF相同数量级的数即可
    if(dist[n] > 0x3f3f3f3f / 2) puts("impossible");
    else cout<<dist[n]<<endl;

    return 0;
}

🚩 运行结果:
约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra

Ⅳ. spfa 求最短路

0x01 算法介绍

夏目学长讲解完毕Bellman-ford算法后,就又给狗蛋讲了一个新的算法知识—spfa算法求最短路。

SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。SPFA 最坏情况下时间复杂度和朴素 Bellman-Ford 相同,为 O(VE)。

spfa算法 属于单源最短路径算法能够求出任意2个顶点之间的最短路径,支持负权边
时间复杂度:O(M * N)

✅ 模板:C++

const int N = 100010;
int h[N], e[N], w[N], ne[N], idx;//邻接表,存储图
int st[N];//标记顶点是不是在队列中
int dist[N];//保存最短路径的值
int q[N], hh, tt = -1;//数组模拟实现队列 也可以使用STL队列

void add(int a, int b, int c){//图中添加边和边的端点
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

void spfa(){
    q[++tt] = 1;//从1号顶点开始松弛,1号顶点入队
    dist[1] = 0;//1号到1号的距离为 0
    st[1] = 1;//1号顶点在队列中
    while(tt >= hh){//不断进行松弛
        int a = q[hh++];//取对头记作a,进行松弛
        st[a] = 0;//取完队头后,a不在队列中了
        for(int i = h[a]; i != -1; i = ne[i])//遍历所有和a相连的点
        {
            int b = e[i], c = w[i];//获得和a相连的点和边
            if(dist[b] > dist[a] + c){//如果可以距离变得更短,则更新距离

                dist[b] = dist[a] + c;//更新距离

                if(!st[b]){//如果没在队列中
                    q[++tt] = b;//入队
                    st[b] = 1;//打标记
                }
            }
        }
    }
}

还没等狗蛋说自己没看懂,夏目学长就开始讲解spfa算法的算法原理了。

0x02 算法原理

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra先明确一下松弛的概念。

  • 考虑节点u以及它的邻居v,从起点跑到v有好多跑法,有的跑法经过u,有的不经过。
  • 经过u的跑法的距离就是distu+u到v的距离。
  • 所谓松弛操作,就是看一看distv和distu+u到v的距离哪个大一点。
  • 如果前者大一点,就说明当前的不是最短路,就要赋值为后者,这就叫做松弛。

然后理解spfa算法的算法原理:

  • 建立一个队列,初始时队列里只有起始点。
  • 再建立一个数组记录起始点到所有点的最短路径(该表格的初始值要赋为极大值,该点到他本身的路径赋为0)。
  • 再建立一个数组,标记点是否在队列中。
  • 队头不断出队,计算始点起点经过队头到其他点的距离是否变短,如果变短且被点不在队列中,则把该点加入到队尾。
  • 重复执行直到队列为空。
  • 在保存最短路径的数组中,就得到了最短路径。

看图解:

  • 给定一个有向图,如下,求A~E的最短路。

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra

  • 源点A首先入队,然后A出队,计算出到BC的距离会变短,更新距离数组,BC没在队列中,BC入队
    约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra
  • B出队,计算出到D的距离变短,更新距离数组,D没在队列中,D入队。然后C出队,无点可更新。

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra

  1. D出队,计算出到E的距离变短,更新距离数组,E没在队列中,E入队。
    约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra
  2. E出队,此时队列为空,源点到所有点的最短路已被找到,A->E的最短路即为8
    约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra
    约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra学完真的是舒服的要飞起来了,不过还有最后一步,加油!

0x02 算法应用

851. spfa求最短路
约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra这次因为是扩展知识,所以夏目学长亲自给狗蛋敲了代码。
💬 代码演示:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 100010;
int h[N], e[N], w[N], ne[N], idx;//邻接表,存储图
int st[N];//标记顶点是不是在队列中
int dist[N];//保存最短路径的值
int q[N], hh, tt = -1;//队列

void add(int a, int b, int c){//图中添加边和边的端点
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

void spfa()
{
    q[++tt] = 1;//从1号顶点开始松弛,1号顶点入队
    dist[1] = 0;//1号到1号的距离为 0
    st[1] = 1;//1号顶点在队列中
    while(tt >= hh){//不断进行松弛
        int a = q[hh++];//取对头记作a,进行松弛
        st[a] = 0;//取完队头后,a不在队列中了
        for(int i = h[a]; i != -1; i = ne[i])//遍历所有和a相连的点
        {
            int b = e[i], c = w[i];//获得和a相连的点和边
            if(dist[b] > dist[a] + c){//如果可以距离变得更短,则更新距离

                dist[b] = dist[a] + c;//更新距离

                if(!st[b]){//如果没在队列中
                    q[++tt] = b;//入队
                    st[b] = 1;//打标记
                }
            }
        }
    }
}
int main()
{
    memset(h, -1, sizeof h);//初始化邻接表
    memset(dist, 0x3f, sizeof dist);//初始化距离
    int n, m;//保存点的数量和边的数量
    cin >> n >> m;
    for(int i = 0; i < m; i++){//读入每条边和边的端点
        int a, b, w;
        cin >> a >> b >> w;
        add(a, b, w);//加入到邻接表
    }
    spfa();
    if(dist[n] == 0x3f3f3f3f )//如果到n点的距离是无穷,则不能到达 
        cout << "impossible";
    else cout << dist[n];//否则能到达,输出距离
    return 0;
}

🚩 运行结果:
约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra

📌 [ 笔者 ]   夏目浅石.
📃 [ 更新 ]   2023.9[ 勘误 ]   /* 暂无 */
📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,
              本人也很想知道这些错误,恳望读者批评指正!

📜 参考文献:

Acwing算法基础课—https://www.acwing.com
《啊哈算法》人民邮电出版社出版—啊哈磊
安阳工学院ACM实验室2023上半年第四周训练题
y总头号粉丝Hasity题解https://www.acwing.com/user/myspace/index/55289/
百度百科[EB/OL]. []. https://baike.baidu.com/.
维基百科[EB/OL]. []. https://zh.wikipedia.org/wiki/Wikipedia
B. 比特科技. C/C++[EB/OL]. 2021[2021.8.31]
C程序设计案例教程 清华大学出版社—钟家民,周晏,张珊靓

约会怎么走到目的地最近呢?一文讲清所有最短路算法问题,💬💡🎈周训,啊哈算法,算法,最短路,dijkstra如果侵权,请联系作者夏目浅石,立刻删除文章来源地址https://www.toymoban.com/news/detail-696510.html

到了这里,关于约会怎么走到目的地最近呢?一文讲清所有最短路算法问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 一文讲清模拟信号、自然信号、数字信号、模拟输入输出

    模拟信号是指在一定周期内进行连续变化的信号,称之为模拟信号,经典的如:电压变化、声波强度变化、温度变化这些自然信号的变化一般称之为模拟信号。 从图中大家可以看到模拟信号的电平变化是逐渐增强与逐渐削弱的,如1v电压-5v电压的变化: 1v-2v-3-4v-5v 从1v逐渐增

    2024年02月08日
    浏览(44)
  • 一文讲清Python的7大学习路线(建议收藏)

    现如今铺天盖地都是来自学习Python的勇士,Python这个编程语言中最友好的语言早已不是高不可攀的状态了。 无论是业余爱好,还是专职求学,学习Python的朋友都在依靠着自己的方法,勤勤恳恳的学习着,但是 学习有方向,入门有方法,进阶更是需要正确的学习方式 。 Pytho

    2023年04月08日
    浏览(47)
  • 【面试】一文讲清组合逻辑中的竞争与冒险

    竞争的定义:组合逻辑电路中,输入信号的变化传输到电路的各级逻辑门,到达的时间有先后,也就是存在时差,称为 竞争 。 冒险的定义:当输入信号变化时,由于存在时差,在输出端产生错误,出现了 瞬时的干扰脉冲 现象,称为冒险(险象)。 通过上面的定义可以得出

    2024年02月11日
    浏览(36)
  • 什么是数字化供应链,一文给你讲清!

    其实数字化供应链是一个很简单的概念,今天就一篇文章给你讲明白! 接下来我将从“是什么,为什么,怎么做”来具体分析,干货不容错过! 说白了就是采购把东西买进来,生产去加工增值,物流去配送给客户,环环相扣,就形成了供应链。 它是由“ 原材料供应-厂家生

    2024年02月04日
    浏览(50)
  • 一文讲清:CRM中的客户概念,如何进行客户管理?

      今天为大家讲解 CRM中客户是什么?如何进行客户管理? CRM系统中有购买意向和已经购买了产品的消费者都属于客户。对于B2B企业,会将企业看作客户,而对于B2C企业来说每一位消费的个体都是客户。 CRM中的客户管理无疑是业务重点,客户资料越完整意味着可以进入下一个

    2024年02月05日
    浏览(49)
  • 【云原生|云原生基础】什么是云原生?一文给你讲清楚!

    云原生(Cloud-Native)是近年来在云计算领域崭露头角的炙手可热的概念。随着云计算技术的不断发展和普及,云原生架构逐渐成为现代应用开发和部署的主流趋势。本文将深入探讨云原生的概念、优势以及重要性,为零基础的读者带来一份全面的入门指南,帮助您了解什么是

    2024年02月12日
    浏览(35)
  • 【Python | 人工智能】一文讲清AI赋能自动驾驶的底层原理

    引言 人工智能引领现代,智能AI赋能未来。 它在当今社会和科技领域中具有重要性。 本文将着重探讨人工智能对自动驾驶技术的深度赋能和应用场景等。 有时我们乘坐网约车的时候,能打到无人驾驶汽车,全程均为AI语音播报: 自动驾驶是指通过使用 各种传感器 、 计算机

    2024年02月04日
    浏览(58)
  • 【数据结构入门精讲 | 第十七篇】一文讲清图及各类图算法

    在上一篇中我们进行了的并查集相关练习,在这一篇中我们将学习图的知识点。 下面介绍几种在对图操作时常用的算法。 深度优先搜索(DFS)是一种用于遍历或搜索树、图等数据结构的基本算法。该算法从给定的起点开始,沿着一条路径直到达到最深的节点,然后再回溯到

    2024年02月03日
    浏览(48)
  • 一文讲清chatGPT的发展历程、能力来源和复现它的关键之处

    chatGPT是什么?这可能是最近被问的最多的一个。 大家第一反应这应该是GPT系列的一个最新模型,普通大众可能更愿意把它看做是一个人工智能。实际上,它其实就是一个基于大规模语言模型的对话系统产品。官网对它定义十分的明确:Optimizing Language Models for Dialogue. 最大的问

    2024年02月03日
    浏览(35)
  • UNIX家族?Windows NT家族?一文讲清操作系统繁杂的家族史

    本专栏更新速度慢,简单讲讲操作系统的那些事,让不是做操作系统开发的同学也能大概认识操作系统这个出现在生活各处的东西 浅淡操作系统系列第0篇 目录 关于专栏 贝尔实验室 UNIX Linux BSD Windows NT 结语 快捷翻页 参考文章 讲操作系统肯定离不开贝尔实验室了,贝尔实验

    2024年02月13日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包