3.21 最短路
创始人
2025-06-01 04:43:42
0

思路

  • 首先设置一个d[i]数组,用于表示从起点到点i最短距离是多少
  • 对于起点来说,d[]=0,对于其他点来说d[]=正无穷
  • 然后遍历n次(n个节点)
  • 假设我们设定一个集合s,表示已经确定最短路径的节点
  • for循环中,每次都选择一个d[]最小的节点放入s中,然后该节点的最短距离就确定了(因为其他节点的d[]都更大,不可能在更新时使得这个d[]最小的节点可以以更短的路径到达)
  • 对于选出的节点t,看其是否能将不在s中的节点的最短路径(d[])更新,如果可以便更新,重复该流程,直到所有节点都被放进s

Dijkstra求最短路 I

这题需要注意的是!
关于0x3f的用法
memset中使用0x3f
但是实际上被赋的值是0x3f3f3f3f

迪杰斯特拉算法边权必须都是正数!!!


#include
#include
#includeusing namespace std;const int N=1e4;
const int M=1e5+10;
int n,m;int h[N],ne[M],e[M],w[M],idx=1;
int s[N];
int d[N];void add(int x,int y,int z){e[idx]=y;ne[idx]=h[x];w[idx]=z;h[x]=idx;idx++;
}void Dijkstra(){memset(d,0x3f,sizeof d);d[1]=0;int min_num;for(int i=1;i<=n;i++){int t;min_num=0x3f3f3f3f;for(int j=1;j<=n;j++){//找到最小的t if(d[j]<=min_num&&s[j]==0){min_num=d[j];t=j;}}s[t]=1;//将t放入已确定最小路径的集合s中//用t更新其他节点的值 for(int p=h[t];p!=-1;p=ne[p]){int j=e[p];if(d[t]+w[p]d[j]=d[t]+w[p];}} }if(d[n]==0x3f3f3f3f)cout<<-1<cin>>n>>m;memset(h,-1,sizeof h);while(m--){int x,y,z;cin>>x>>y>>z;add(x,y,z);}Dijkstra(); return 0;
}

优化

我们可以很容易的看出迪杰斯特拉算法中最耗时的一步是查找当前的最小d[],这个的时间复杂度是n方
很容易想到使用堆来解决,这样每次查找最小值就是O(1)

直接使用priority_queue, 头文件是#include
**priority_queue<数据类型, vector<数据类型>, greater<数据类型>> heap; ** 这是定义的格式,记住。
greater是小顶堆,less是小顶堆
特别要注意的是!!
当数据类型是int等类型时,自然而然就排序了。
但是,当使用类型是PII等类型时候,优先排序第一个元素!!!然后再排序第二个元素!
所以本题中将distance放在PII的第一个元素!
当然也可以指定排序方式,见下面的链接

指定priority_queue排序方式


#include
#include
#includeusing namespace std;const int N=1e6+10;
int n,m;int h[N],ne[N],e[N],w[N],idx=1;
int s[N];
int d[N];typedef pair  PII;void add(int x,int y,int z){e[idx]=y;ne[idx]=h[x];w[idx]=z;h[x]=idx;idx++;
}void Dijkstra(){priority_queue, greater> heap;memset(d,0x3f,sizeof d);d[1]=0;heap.push({0,1});while(heap.size()){auto t=heap.top();heap.pop();int v=t.second;	if(s[v])	continue;s[v]=1;for(int p=h[v];p!=-1;p=ne[p]){int j=e[p];if(d[v]+w[p]d[j]=d[v]+w[p];heap.push({d[j],j}); }} }if(d[n]==0x3f3f3f3f)cout<<-1<cin>>n>>m;memset(h,-1,sizeof h);while(m--){int x,y,z;cin>>x>>y>>z;add(x,y,z);}Dijkstra(); return 0;
}

Bellman-ford算法

Bellman-ford算法虽然在写法上和迪杰斯特拉很像,但是本质完全不同
Dijkstra算法是每次找到一个最短路径确定的点,然后对该点能到达的路径进行更新,因此需要执行n次
但是Bellmax-ford算法是对边进行遍历,首先外层循环规定了两点之间最多可以走k次边,内层循环则是对所有的
边进行遍历,然后更新。
介绍一下负环,就是如下情况:
在这里插入图片描述
由于出现了2+(-3)+(-1)<0的情况,因此A->B如果想走最短路径的话就会无限重复这个环
在bellman算法中,每次进行最短路径的更新,那么如果从1到n有路径的话,那么最多n-1条路径(n个点)就可以到达。
如果循环到了n或者更大,那么说明一定存在负环了
不过一般不用bellman找负环,这里记住就可以了(一般用spfa找负环)
bellman算法一般用于有边数限制的最短路径查找

需要使用一个last数组记录之前状态,原因如下:

在这里插入图片描述

上面的图可能看起来有点抽象,我来解释一下:
首先右上角的是原路线图,如果我们不设置last,那么对于k=1的时候,意思是我们只找1条边能到达的最短路径
假如首先遍历1->2这条边,dist[2]被更新为1,然后我们扫描到2->3这条边,此时使用:
dist[3]=min(dist[3],dist[2]+w_2->3),那么dist[3]就被更新成为2,但是这里的dist[2]是使用过一次边的情况,因此这样的更新是错误的
我们需要采用下面的方法,使用一个last数组,用于记录更新前的状态,即图中绿色的(0,+无穷,+无穷)。
然后更新后面的值的时候根据last数组更新就不会出现错误了,过程为:
dist[2]=1,然后dist[3]首先会被更新成为正无穷,因为用dist[2]=+无穷更新的,然后扫描到1->3这条边的时候才会被更新为dist[3]=3
这里使用memcpy复制,memcpy(a,b,sizeof b), 将b的数据复制到a中
注意是在外层的for内部每一次进行复制

还有一件事,如何确定某一个点走不到呢
题目中给定k<500,且每条路径长度绝对值不超过10000.
那么如果能走到一定在51e6内,
为什么不用dist[n]==0x3f3f3f3f判定呢,因为0x3f3f3f3f是一个值,而存在负边。
假设节点m距离节点n的距离是-1,而节点m距离1的距离是正无穷,
实际上dist[n]会被更新为正无穷-1,在本题中就是0x3f3f3f3f-1,并不等于0x3f3f3f3f
但是由于长度有范围,所以我们认为长度在0x3f3f3f3f/2之内的数据都表示能到达 (1e9/2 ) ,因为上面估计5
1e6都能到

🆗,代码可以写了


#include
#include
#includeusing namespace std;const int N=1e4+10;int n,m,k;struct node{int a,b,w;
} edge[N];int dist[N];
int last[N]; void bellman(){dist[1]=0;for(int i=1;i<=k;i++){//可选k次边 memcpy(last,dist,sizeof dist);for(int j=1;j<=m;j++){//遍历m条边 int a=edge[j].a;int b=edge[j].b;int w=edge[j].w;dist[b]=min(dist[b],last[a]+w);} }}int main(){cin>>n>>m>>k;int x,y,z;for(int i=1;i<=m;i++){cin>>x>>y>>z;edge[i]={x,y,z};}memset(dist,0x3f,sizeof dist);bellman();if(dist[n]>0x3f3f3f3f/2)cout<<"impossible"<

相关内容

热门资讯

现代诗歌金波 现代诗歌金波(精选7首)  在日常生活或是工作学习中,大家一定都接触过一些使用较为普遍的诗歌吧,诗歌...
月亮边的妹妹诗歌 月亮边的妹妹诗歌  遥遥银河边缘  悠悠白云深处  驻守着我的妹妹  美丽善良的妹妹  你是晚霞疲惫...
歌颂劳动者的诗歌朗诵 歌颂劳动者的诗歌朗诵(精选13首)  无论在学习、工作或是生活中,大家都收藏过自己喜欢的诗歌吧,诗歌...
题李凝幽居诗词赏析 题李凝幽居诗词赏析  【诗人简介】  贾岛:(779-843),字阆仙,范阳(今北京)人。早年出家为...
语文诗词的手抄报 关于语文诗词的手抄报  导语:诗词,是指以古体诗、近体诗和格律词为代表的中国古代传统诗歌。亦是汉字文...
对李白《行路难》的赏析 对李白《行路难》的赏析  在日常的学习、工作、生活中,大家都经常接触到诗歌吧,诗歌具有精炼含蓄的特点...
爱情古诗句唯美图片 爱情古诗句唯美图片  不要承诺,不要誓言,只要用一杯茶的温度,品茗一生的幸福。有一种牵挂,在心底反复...
雨霖铃柳永全文及翻译 雨霖铃柳永全文及翻译  《雨霖铃·寒蝉凄切》是宋代词人柳永的词作。此词上片细腻刻画了情人离别的场景,...
林清玄《阳光的味道》全文 林清玄《阳光的味道》全文  林清玄中国著名文化学者,理论家、文化史学家、作家 、散文家。下面是《阳光...
汪藻《春日》原文及译文 汪藻《春日》原文及译文  《春日》是北宋诗人汪藻创作的一首七言律诗。这首诗通过对春日出游的见闻感受的...
于春的诗句 于春的诗句  1) 满目山河空念远,落花风雨更伤春。 ——出处: 晏殊《浣溪沙•一向年光有...
与颜色有关的诗句 与颜色有关的诗句  诗句就是组成的句子。诗句通常按照诗文的格式体例,限定每句字数的多少。以下是小编帮...
梁实秋《雅舍谈吃》散文集:《... 梁实秋《雅舍谈吃》散文集:《满汉细点》  引导语:《雅舍谈吃》是梁实秋先生一生在饮食文化方面才华的集...
浣溪沙姜夔赏析诗词 浣溪沙姜夔赏析诗词  浣溪沙,原为唐教坊曲名,后用为词牌名。此调分平仄两体,字数以四十二字居多,另有...
晨起动征铎,客行悲故乡 “晨起动征铎,客行悲故乡。”出处 出自 唐代 温庭筠 的《商山早行》“晨起动征铎,客行悲故乡。”全诗...
教师节我想对老师说的话   教师节马上就要到了,想好了要怎么祝福老师吗?下面小编就为大家整理了教师节我想对老师说的话,欢迎阅...
好听唯美的诗句诗词 好听唯美的诗句诗词大全  在学习、工作乃至生活中,大家都看到过许多经典的诗句吧,诗句是诗的句子,泛指...
八月中秋诗句有哪些 八月中秋诗句有哪些  在我们平凡的日常里,说到诗句,大家肯定都不陌生吧,诗句一般饱含丰富的'想象、联...
新春的诗句有哪些 新春的诗句有哪些  春节起源于殷商时期年头岁尾的祭神祭祖活动,是中国最盛大、最热闹、最重要的一个古老...
“不知细叶谁裁出,二月春风似... “不知细叶谁裁出,二月春风似剪刀。”出处:唐·贺知章《咏柳》 [意思]不知那丝丝柳叶是谁裁出,原来二...