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

news2024/12/27 4:10:19

      🚀🚀🚀🚀🚀订阅专栏👉 趣学算法(dog) 👈 带你学习算法原理 + 算法模板🚀🚀🚀🚀🚀
在这里插入图片描述

write in front

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


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

在这里插入图片描述 约会完成后的狗蛋在想,在计算机里面我们该如何找到去到万达广场最短的路呢? 在好奇心的驱使下,他找到了夏目学长来帮助他解决问题。

Ⅰ. Floyd 求最短路

0x00 算法介绍

在这里插入图片描述夏目学长听到狗蛋的问题后 立刻给狗蛋说出了一个词 “Floyd算法” 然后说:先学习Floyd算法来打基础,进而解决你所面临的问题。

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

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

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

在这里插入图片描述这里先给出算法模板,然后进行讲解。

✅ 模板: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 算法原理

在这里插入图片描述夏目学长身为《啊哈算法》的粉丝就拿出了《啊哈算法》书上的算法例子了。

在这里插入图片描述
上图中有4个城市8条公里,公路上的数字表示这条公路的长短,并且公里是单向的,现在夏目学长要求我们求出任意两个城市之间的最短路程,也就是求任意两个点之间的最短路经,这就是多源最短路问题

请添加图片描述我们可以使用二维数组e (邻接矩阵) 来存储信息。比如1号城市到2号城市的路程为2,则e[1][2] = 2,2号城市无法到达4号城市,则设置为0x3f3f3f3f(最大值相当于正无穷大) ,城市自己到自己的距离为0,也就是e[1][1]=0 。

在这里插入图片描述

在这里插入图片描述于是夏目学长让狗蛋思考如何让任意两点之间的距离变短?

在这里插入图片描述当然是:只能引入第三个点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,通过这个例子狗蛋明白了:每个顶点都有可能使得另外两个顶点之间的路程变短

在这里插入图片描述夏目学长又说:假设我们只允许经过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]即可

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

在这里插入图片描述这个时候狗蛋觉得自己行了,就让夏目学长给他出一个算法题…

0x02 算法应用

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

854. Floyd求最短路

请添加图片描述狗蛋看到后思索了一番便写出了代码:
💬 代码演示:

#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;
}

🚩 运行结果:
在这里插入图片描述
如果想进一步练习Floyd算法的话👉 Floyd算法+并查集算法专题训练👈详细看这篇博客所写的内容和题目,帮你迅速掌握这个算法

Ⅱ. Dijkstra 求最短路

0x00 算法介绍

在这里插入图片描述当狗蛋学会了Floyd最短路算法之后,内心就开始蠢蠢欲动了,还没等到夏目学长开口,狗蛋就打算自己动手用Floyd算法去求自己到达万达广场的最短路,于是他像晚上打codeforces那样坐牢了起来,迟迟不见他敲代码,于是他突然想到夏目学长说过Floyd算法好像是求得多源最短路问题,而他实际遇到的是单源最短路问题,这时夏目学长才语重心长的说,不用着急,等你学会了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];

}

在这里插入图片描述估计在这里看到模板,你会和狗蛋一样,一下子就蒙了,不过没关系,下面夏目学长就开始讲解算法原理

0x01 算法原理

在这里插入图片描述夏目学长就在黑板上画了一张这样得图,来帮助狗蛋理解Dijkstra算法原理。

在这里插入图片描述

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

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

  2. 用一个状态数组 st 记录是否找到了源点到该节点的最短距离,st[i]
    如果为真,则表示找到了源点到城市 i 的最短距离,st[i]
    如果为假,则表示源点到城市 i 的最短距离还没有找到。
    初始时,st 各个元素为假(false)
    在这里插入图片描述

  3. 然后先把我们的起点初始化一下,也就是dist[1] = 0,接着我们找到1号城市可以到达的城市的最近的城市,显然我们举得例子是2号城市,
    在这里插入图片描述

  4. 遍历 dist 数组,找到一个节点,这个节点是:没有确定最短路径的节点中距离源点最近的点。假设该节点编号为 i。此时就找到了源点到该节点的最短距离,st[i] 置为 true。
    在这里插入图片描述

  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]。
    在这里插入图片描述

  6. 重复 3 4 步骤,直到所有节点的状态都被置为 1。
    在这里插入图片描述

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

在这里插入图片描述这个时候算法原理就讲解完毕了,勇敢狗蛋不怕困难,开始了算法实现,然后夏目学长问他,你知道为什么Dijkstra算法不能求负权边么? 狗蛋挠挠头说不知道,于是夏目学长就徐徐道来:
dijkstra不能解决负权边是因为 dijkstra要求每个点被确定后st[j] = truedist[j]就是最短距离了,之后就不能再被更新了 (一锤子买卖)而如果有负权边的话,那已经确定的点的dist[j]不一定是最短了

0x02 算法应用

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

请添加图片描述狗蛋像是奖励自己一样,扑到电脑面前,写起了代码
💬 代码演示:

#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,spfa,图论二分图算法AYIT—ACM训练(模板版)👈详细看这篇博客所写的内容和题目,帮你迅速掌握这个算法

Ⅲ. bellman-ford 求最短路

0x01 算法介绍

在这里插入图片描述当狗蛋以为自己能够挑战所有的最短路的题目的时候,突然遇到了一道有边数限制的最短路问题,于是他又屁颠屁颠的找到了夏目学长进行求教,这是不是很好的一种品质呢?不断学习,不断求教,不断进步!

于是夏目学长看到了算法题的题目如下:
在这里插入图片描述
在这里插入图片描述看完后夏目学长 哦~ 了一声,就跟狗蛋说,这是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);//松弛操作
        }
    }
}

在这里插入图片描述大家看到这里肯定和狗蛋一样一头雾水,下面就给大家讲解一下算法原理。♪ (・ω・)ノ

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. 有边数限制的最短路

请添加图片描述狗蛋按照自己的理解,学出了代码。
💬 代码演示:

#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;
}

🚩 运行结果:
在这里插入图片描述

Ⅳ. 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 算法原理

在这里插入图片描述 先明确一下松弛的概念。

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

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

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

看图解:

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

在这里插入图片描述

  • 源点A首先入队,然后A出队,计算出到BC的距离会变短,更新距离数组,BC没在队列中,BC入队
    在这里插入图片描述
  • B出队,计算出到D的距离变短,更新距离数组,D没在队列中,D入队。然后C出队,无点可更新。

在这里插入图片描述

  1. D出队,计算出到E的距离变短,更新距离数组,E没在队列中,E入队。
    在这里插入图片描述
  2. E出队,此时队列为空,源点到所有点的最短路已被找到,A->E的最短路即为8
    在这里插入图片描述
    在这里插入图片描述学完真的是舒服的要飞起来了,不过还有最后一步,加油!

0x02 算法应用

851. spfa求最短路
请添加图片描述这次因为是扩展知识,所以夏目学长亲自给狗蛋敲了代码。
💬 代码演示:

#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;
}

🚩 运行结果:
在这里插入图片描述

在这里插入图片描述

📌 [ 笔者 ]   夏目浅石.
📃 [ 更新 ]   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程序设计案例教程 清华大学出版社—钟家民,周晏,张珊靓

在这里插入图片描述如果侵权,请联系作者夏目浅石,立刻删除

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/979463.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android Studio开发入门教程:如何更改APP的图标?

更改APP的图标&#xff08;安卓系统&#xff09; 环境&#xff1a;Windows10、Android Studio版本如下图、雷电模拟器。 推荐图标库 默认APP图标 将新图标拉进src/main/res/mipmap-hdpi文件夹&#xff08;一般app的icon图标是存放在mipmap打头的文件夹下的&#xff09; 更改sr…

Java File类和IO流

1. File类 1.1 File对象创建 注意&#xff1a; 路径中"\"要写成"\\"&#xff0c; 路径中"/"可以直接用 File对象可以指代一个不存在的文件路径路径中带盘符是绝对路径&#xff0c;不带盘符是相对路径 1.2 File判断和获取方法 1.3 创建和删除方…

Kafka3.0.0版本——增加副本因子

目录 一、服务器信息二、启动zookeeper和kafka集群2.1、先启动zookeeper集群2.2、再启动kafka集群 三、增加副本因子3.1、增加副本因子的概述3.2、增加副本因子的示例3.2.1、创建topic(主题)3.2.2、手动增加副本存储 一、服务器信息 四台服务器 原始服务器名称原始服务器ip节点…

企业架构LNMP学习笔记15

客户端缓存&#xff1a; B/S架构里&#xff0c;Browser是浏览器&#xff0c;就是客户端。 客户端缓存告知浏览器获取服务段的信息是在某个区间时间段是有效的。 每次请求从服务器拿一遍数据&#xff0c;数据没有变化&#xff0c;影响带宽&#xff0c;影响时间。刷新又要去加载…

百度飞桨(武汉)人工智能产业赋能中心签约,推动AI技术与汉阳“1+6”产业深度融合

9月1日&#xff0c;“文心中国行”首站落地武汉汉阳。活动现场&#xff0c;武汉市汉阳区与百度正式签约&#xff0c;共同打造百度飞桨&#xff08;武汉&#xff09;人工智能产业赋能中心&#xff0c;助力武汉产业高质量跨越式发展。活动围绕“深入解读大模型产业实践&#xff0…

UWB学习——day1

UWB定义 UWB&#xff1a;Ultra Wideband&#xff08;超宽频&#xff09; UWB所谓的超宽频区别于其它近场通信技术可总结为时域上跳跃&#xff0c;频域上矮胖 从图中可以看出&#xff0c;时域上通过短且强的脉冲信号&#xff0c;频域上主要是超宽的频谱&#xff08;Spectrum&a…

979. 在二叉树中分配硬币;1136. 并行课程;759. 员工空闲时间

979. 在二叉树中分配硬币 核心思想&#xff1a;递归。定义dfs(node)&#xff0c;返回值为以当前节点为根节点的节点个数和硬币个数。 那么这棵树至少需要移入或者移出abs&#xff08;coins-nodes&#xff09;个硬币&#xff0c;也就是这么多步&#xff0c;然后累计它们的总和…

aarch64 arm64 部署 stable diffusion webui 笔记 【2】继续安装其他依赖 gfpgan

接上篇 aarch64 arm64 部署 stable diffusion webui 笔记 【1】准备 venv 安装pytorch 验证cuda_hkNaruto的博客-CSDN博客 编辑requirements_versions.txt&#xff0c;注释掉torch 启动webui.sh (venv) [rootceph3 stable-diffusion-webui]# useradd yeqiang useradd&#xf…

Pocket Yoga for mac:一个神奇的瑜伽助手,让你的身心更健康

Pocket Yoga for Mac&#xff08;口袋瑜伽&#xff09;是一款专为瑜伽爱好者设计的应用程序。无论您是初学者还是经验丰富的瑜伽修行者&#xff0c;这款应用都能帮助您在家中或办公室进行高效的瑜伽练习。 Pocket Yoga for Mac提供了一系列的瑜伽课程和练习&#xff0c;涵盖了不…

信息安全基础-技术体系-加密技术

系统安全 考点分析信息安全的基础知识&#xff08;重点&#xff09;信息安全系统的组成框架信息安全技术对称加密技术非对称加密对称密钥和非对称密钥对比 考点分析 一般不超纲 信息安全的基础知识&#xff08;重点&#xff09; 五个基本要素经常考察 机密性&#xff1a;加密报…

Python接口自动化测试框架介绍

之前在项目中搞了一套jmeter jenkins git ant接口自动化测试框架&#xff0c;在项目中运行了大半年了&#xff0c;效果还不错&#xff0c; 最近搞了一套requests unittest ddt pymysql BeautifulReport的接口自动化测试框架&#xff0c; 测试用例在yaml文件中&#xff0c…

Android后退堆栈

修改代码 现在的ItemClick使得用户单击其中一个项目时就会跳转&#xff0c;现在要修改其使得在一个小屏幕设备上才会这样做&#xff0c;在一个大屏幕设备上运行用户选择一个训练项目时在右边的片段显示响应的信息。 希望片段处理后退的方式&#xff1a;假设用户在手机上运行这…

游戏AI综述

1、游戏AI的特点 随着深度学习等技术的突破性进展&#xff0c;现代的人工智能技术进步神速&#xff0c;已经在自然语言处理、机器翻译和图像识别等众多方面取得了进步&#xff0c;而且已经影响到了现实生活。 如果把围棋也看作游戏&#xff0c;那么大名鼎鼎的AlphaGo系列人工…

使用SimpleITK批量计算医学图像分割的mask体积,病灶体积

使用SimpleITK计算如下所示的病灶标注的整体体积。 可以在该代码的基础上&#xff0c;增加写入excel表的操作&#xff0c;这样就可以把模型推理前的体积和模型推理后的体积都写入excel表&#xff0c;然后进行一系列分析。 1 计算方式 用SimpleITK包进行ROI/病灶体积的计算 im…

C高级day1

一、用cut截取出用户的家目录。要求&#xff1a;不能用“&#xff1a;”作为分割 二、XMind思维导图

el-table纵向垂直表头

参考&#xff1a;https://www.jianshu.com/p/1f38eaffd070 <el-tablestyle"width: 100%":data"getValues":show-header"false"border:cell-style"cellStyle" ><el-table-columnv-for"(item, index) in getHeaders"…

两种解法解决 LeetCode 27. 移除元素【C++】

移除元素 27. 移除元素题目&#xff1a;[移除元素](https://leetcode.cn/problems/remove-element/description/)示例和提示&#xff1a;解法&#xff1a;1. 暴力解法 2. 快慢指针 27. 移除元素 题目&#xff1a;移除元素 示例和提示&#xff1a; 解法&#xff1a; 1. 暴力解…

【C++】DICOM医学影像工作站PACS源码

PACS即影像存档与传输系统&#xff0c;是医学影像、数字化图像技术、计算机技术和网络通讯技术相结合的产物&#xff0c;是处理各种医学影像信息的采集、存储、报告、输出、管理、查询的计算机应用程序。 PACS是基于DICOM标准的医学影像管理系统&#xff0c;其模块覆盖了从影像…

Java:ArrayList源码解析

Java&#xff1a;ArrayList源码解析 导言 我们都知道ArrayList是一个可以实现自动扩容的List类&#xff0c;为了理解ArrayList是如何进行扩容的&#xff0c;我们就有必要对ArrayList的源码进行分析。本文中将着重研究源码中ArrayList是如何实现自动扩容的。 源码解析 ArrayL…

合宙Air724UG LuatOS-Air LVGL API控件-页面 (Page)

页面 (Page) 当控件内容过多&#xff0c;无法在屏幕内完整显示时&#xff0c;可让其在 页面 内显示。 示例代码 page lvgl.page_create(lvgl.scr_act(), nil) lvgl.obj_set_size(page, 150, 200) lvgl.obj_align(page, nil, lvgl.ALIGN_CENTER, 0, 0)label lvgl.label_crea…