三种求最短路算法基本描述及实现(C++)

article/2025/9/23 14:50:04

比较:

FloyedDijkstra(优先队列优化)SPFA(优先队列优化)
时间复杂度o(n^3)o(n+m)(logm)o(km)
基本思想动态规划贪心贪心
适用范围无负环图无负权图无负环图
多源最短路不含负权图的低复杂度解含负权边时的单源最短路求解

1.Floyed算法

变量声明:

n,N        点的数量

m, M        边的数量

G[ x ][ y ]        图,表示从 x 点到 y 点的边的权值

dis[ i ][ j ]        路径,表示当前情况下 i 点到 j 点的最短路径长度

算法简洁描述:

通过不断选取中间点来更新从点 i 到点 j 的最短路径

更新方式:

将现有的点 i 到 j 的最短距离 与 已知点 i 到中间点 k 的最小距离 + k 到 j 的路径距离 进行比较

公式表述:

dis[ i ][ j ] = min( dis[ i ][ j ] ,  dis[ i ][ k ] + G[ k ][ j ] )

循环次序:

for temp in spot:for start in spot:for end in spot:

基本实现:

目标:

读入一个含有n条边的无负环无向图,求出图中任意两点之间的最短路径

代码:

#include <bits/stdc++.h>
using namespace std;
//n->点数 m->边数 
#define N 1000
#define M 2000
int n, m;
//邻接矩阵图数组 
int G[N+1][N+1];
//最短路数组 
int dis[N+1][N+1];
//算法内容 
void Floyed()
{for(int k = 1; k <= n; k++){	//中间点 for(int i = 1; i <= n; i++){	//起始点 if(i == k) continue;for(int j = 1; j <= n; j++){	//末尾点 if(i == j) continue;dis[i][j] = min(dis[i][j], dis[i][k] + G[k][j]); }}}	
}int main(void)
{memset(dis, 0x3f, sizeof(dis));scanf("%d%d", &n, &m);//读入无负环无向图 for(int i = 1; i <= m; i++){int x, y, v;scanf("%d%d%d", &x, &y, &v);G[x][y] = G[y][x] = v;}Floyed();return 0;
}

2.Dijkstra算法

变量声明:

n, N       图的点
m, M      图的边

start       起始点

INF        无穷大
链式前向星edge      x 点下标, v 边权值, next 连接点
vis[ i ]         标记从起始点到点 i 的最短路径是否已经更新
dis[ i ]         表示从起始点到点 i 的最短路径值
结构体 ty        收纳点信息,包括点下标 x 和最短路径值 dis
priority_queue<ty>q;       边权升序排列的优先队列

算法简洁描述:

以既定起点的最短路径值为 0 开始,不断地从当前已确定最短路径的点中选取dis值最小的点,用选取点去更新所有相邻点的最短路径

过程描述:

1.更新起始点 dis 为 0,将起始点的信息(下标 和 dis值) 放进优先队列

2.从优先队列中取出一个未用于更新且 dis 值最小的点信息,然后将该点信息丢出队列

3.用取出的点去更新邻近点的 dis 值,并将新更新的点的信息放进优先队列

4.重复2、3操作,直到优先队列元素为空

其实如果利用优先队列优化,而且每个队列元素拿出来用完就丢掉,就不需要判断取出的点是否曾用于更新,这里为了突出这个先决条件,特意声明

简单实例模拟(变量意义看上述):

 现在求从点 1 到各点的最短路径值:

12345678
dis[1]vis[1]dis[2]vis[2]dis[3]vis[3]dis[4]vis[4]dis[5]vis[5]dis[6]vis[6]dis[7]vis[7]dis[8]vis[8]
初始化更新起点的dis值为0,其余dis值为INF,起点最短路径已确定,vis为true
0TINFFINFFINFFINFFINFFINFFINFF
第一次更新与起点邻接的点有3、4、2,更新dis,vis
0T0+6T0+5T0+2TINFFINFFINFFINFF
第二次更新在已经更新的点中选取dis最小且未用于更新最短路的点4作为新的起点,更新所有能更新的最短路径,这次只有点5可更新
0T6T4T2T2+4TINFFINFFINFF
第三次更新选取已经更新的点中dis值最小且未用于更新最短路的点3作为起点,更新最短路
0T6T4T2T6T4+5T4+6TINFF
第四次更新继续按上述方式选点,出现dis相同的两点,发现选择点2已经不能更新,所以选择点5
0T6T4T2T6T9T10T6+7T

与计算机跑出的结果相同:

基本实现:

目标:

读入一个含有 n 个点的无负权无向图,求出图中从起始点 start 到任意点的最短路径

代码:

#include<bits/stdc++.h>
using namespace std;
//边&点 
#define N 100000
#define M 200000
int n, m, start;
//链式前向星存图 
int cnt = 0, head[M+1];
struct Node{int x, v, next;
}edge[2*N+1];
void addedge(int x, int y, int v)
{edge[++cnt].v = v;edge[cnt].x = y;edge[cnt].next = head[x];head[x] = cnt;
}
//
int dis[N+1];
bool vis[N+1];
struct ty{int dis, x;bool operator < (const ty &a) const{return dis > a.dis;} 
}temp;
priority_queue<ty>q;
//Dijkstra算法
void Dijkstra(int st)
{//将初始点信息放进队列dis[st] = 0;temp.dis = 0; temp.x = st;q.push(temp);//while(!q.empty()){//找到当前队列中边权最小点temp = q.top(); q.pop();int x = temp.x;if(vis[x]) continue;vis[x] = true;//利用取出的点更新最短路for(int i = head[x]; i != -1; i = edge[i].next){int node = edge[i].x;//将可更新点更新,并放进队列if(dis[node] > dis[x] + edge[i].v){dis[node] = dis[x] + edge[i].v;ty ne;ne.dis = dis[node]; ne.x = node;q.push(ne);}}}
} int main(void)
{memset(head, -1, sizeof(head));memset(dis, 0x3f, sizeof(dis));memset(vis, false, sizeof(vis));//存图scanf("%d%d", &n, &m);for(int i = 1; i <= m; i++){int x, y, v;scanf("%d%d%d", &x, &y, &v);addedge(x, y, v);addedge(y, x, v);}	scanf("%d", &start); Dijkstra(start);return 0;
} 

3.SPFA算法

变量声明

n, N       图的点
m, M      图的边

start       起始点
链式前向星edge      x 点下标, v 边权值, next 连接点
vis[ i ]         标记从起始点到点 i 的最短路径是否已经更新
dis[ i ]         表示从起始点到点 i 的最短路径值
queue<int>q;       存放点下标的队列

简洁描述:

SPFA思路和过程都和Dijkstra相似,不同的是SPFA不会去研究被用于更新最短路的点dis值是否是最小的

过程描述:

1.更新起始点 dis 为 0,放进队列

2.从队列中取出一个点

3.用取出的点更新所有与其相邻的点的 dis 。并且,如果当前队列中没有新更新过的点,就将新更新的点放进队列

4.重复2、3操作,直到队列为空

基本实现:

目标:

读入一个含有 n 个点的无负权无向图,求出图中从起始点 start 到任意点的最短路径

代码:

#include<bits/stdc++.h>
using namespace std;
//边&点 
#define N 100000
#define M 200000
int n, m, start;
//链式前向星存图 
int cnt = 0, head[M+1];
struct Node{int x, v, next;
}edge[2*N+1];
void addedge(int x, int y, int v)
{edge[++cnt].v = v;edge[cnt].x = y;edge[cnt].next = head[x];head[x] = cnt;
}
//
int dis[N+1];
bool vis[N+1];
queue<int>q;
//SPFA
void spfa(int st)
{//起点初始化,放进队列 dis[st] = 0; vis[st] = 1;q.push(st);while(!q.empty()){//拿出队首元素 int x = q.front(); q.pop();vis[x] = false;//更新最短路径值 for(int i = head[x]; i != -1; i = edge[i].next){int ne = edge[i].x;if(dis[ne] > dis[x] + edge[i].v){dis[ne] = dis[x] + edge[i].v;//如果该元素现在不在队列,放进队列 if(!vis[ne]){q.push(ne);vis[ne] = true;}}}}
} 
int main(void)
{memset(dis, 0x3f, sizeof(dis));memset(vis, false, sizeof(vis));memset(head, -1, sizeof(head));//存图scanf("%d%d", &n, &m);for(int i = 1; i <= m; i++){int x, y, v;scanf("%d%d%d", &x, &y, &v);addedge(x, y, v);addedge(y, x, v);}	scanf("%d", &start); spfa(start);//输出计算结果 for(int i = 1; i <= n; i++){printf("dis %d: %2d    ", i, dis[i]);if(i %2 == 0) cout <<endl;} return 0;
} 


http://chatgpt.dhexx.cn/article/NMjRCgLn.shtml

相关文章

python中0x3f_单片机中0x3f代表什么意思

展开全部 单片机中0x3f代表16进制数62616964757a686964616fe78988e69d83313334313566623F&#xff0c;即0011 1111B或63D(B代表二进制&#xff0c;D代表十进制)&#xff0c;在单片机中常用于配置IO口的输入输出或寄存器的相关配置&#xff0c;实际意义指二进制对应位为高电平。…

51单片机LED数码管

LED显示器分为共阴极&#xff08;发光二极管所有的阴极连接在一起&#xff09;和共阳极&#xff08;所有的阳极都连接在一起&#xff09;两种。 共阴高电平有效 共阳低电平有效 char led[] {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; 共阴接法0~9 共阳取反就行 …

单片机 0xff是什么意思

0x是16进制的前缀。单片机中对寄存器或IO口操作都是用十六位进制表示&#xff0c;比如oxaa&#xff0c;代表二进制的1010&#xff08;a&#xff09; 1010&#xff08;a&#xff09;。在书写时0x代表十六位进制。 16进制就是逢16进1&#xff0c;但我们只有0~9这十个数字&#x…

python中0x3f_类似于0x3F是什么意思?怎么转换?

展开全部 单片机中0x3f代表16进制数3F&#xff0c;即00111111B或63D(B代表二进制&#xff0c;D代表十进制)&#xff0c;在单片机中常用于配置62616964757a686964616fe78988e69d8331333436316265IO口的输入输出或寄存器的相关配置&#xff0c;实际意义指二进制对应位为高电平。 …

c++ 0x3f 0x3f3f 0x3f3f3f 0x3f3f3f3f的具体值

RT&#xff0c;做题的时候因为没有把最大值设置好&#xff0c;导致有一个点没有过去。现在记录一下0x3f之类的数值&#xff0c;以方便日后的使用 0x3f&#xff1a;代表的数值63 0x3f3f&#xff1a;代表的数值16191 10的四次方多 0x3f3f3f&#xff1a;代表的数值4144959 10的六…

0x3f3f3f3f是什么意思

经常会看到大佬的定义中出现有一些这样的东西&#xff0c;经过多方印证查阅可以找到介绍讲解 0x3f3f3f3f的十进制是1061109567&#xff0c;是10^9级别的&#xff0c;而一般场合下的数据都是小于10^9的&#xff0c;所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。 …

图论中的0x3f和memset使用注意事项(较详细)

图论中的memset和0x3f 写此博客的背景 相信有很多同学在看别人图论专题的题解、板子的时候经常看到下面两句&#xff1a; const int INF 0x3f3f3f3f; memset(d, INF, sizeof(d));或者下面这样&#xff1a; memset(d, 0x3f, sizeof(d));很多同学都不明所以&#xff0c;只知…

双三次插值算法

配合阅读&#xff1a;https://blog.csdn.net/nandina179/article/details/85330552 今天学习了第三种图像缩放的方法&#xff0c;双三次插值法。由于理解能力比较差&#xff0c;看了好久的公式&#xff0c;还是云里雾里&#xff0c;但是为了督促自己学习&#xff0c;还是把已知…

图像的放大:双三次插值算法(C++实现)

双线性插值算法的不足就是细节处理的不好&#xff0c;换句话说&#xff0c;就是曲线拟合得不够光滑&#xff0c;所以又有了双三次插值算法。双三次插值算法是基于周围的16个像素点&#xff0c;通过计算16个像素点的权重&#xff0c;累积得到增加点的像素值的。 简单点理解&…

图像插值理论研究——双三次插值(双立方插值)

双三次插值&#xff0c;英文是Bicubic interpolation。双三次插值是一种更加复杂的插值方式&#xff0c;它能创造出比双线性插值更平滑的图像边缘。双三次插值方法通常运用在一部分图像处理软件、打印机驱动程序和数码相机中&#xff0c;对原图像或原图像的某些区域进行放大。A…

FPGA图像处理HLS实现三种图像缩放算法,线性插值、双线性插值、双三次插值,提供HLS工程和vivado工程源码

目录 一、三种图像缩放算法介绍线性插值双线性插值双三次插值 二、HLS实现线性插值图像缩放三、HLS实现双线性插值图像缩放四、HLS实现双三次插值图像缩放五、HLS在线仿真并导出IP六、其他FPGA型号HLS在线仿真并导出IP七、zynq7100开发板vivado工程八、上板调试验证九、福利&am…

数字图像处理100问—27 双三次插值( Bicubic Interpolation )

提示&#xff1a;内容整理自&#xff1a;https://github.com/gzr2017/ImageProcessing100Wen CV小白从0开始学数字图像处理 27 双三次插值&#xff08; Bicubic Interpolation &#xff09; 使用双三次插值将图像放大1.5倍 双三次插值是双线性插值的扩展&#xff0c;使用邻域…

用于数字成像的双三次插值技术​

点击上方“小白学视觉”&#xff0c;选择加"星标"或“置顶” 重磅干货&#xff0c;第一时间送达 双三次插值是使用三次或其他多项式技术的2D系统&#xff0c;通常用于锐化和放大数字图像。在图像放大、重新采样时&#xff0c;或是在软件中润饰和编辑图像时也会使到用…

插值算法(最邻近差值、双线性插值、双三次插值)

一、最邻近差值&#xff08;nearest&#xff09; 含义&#xff1a; 选取离目标点最近的点的值作为新的插入点的值。 两幅图坐标值变换关系&#xff1a; &#xff08;代码未验证&#xff09; for i1:size(dist,1)x round(i* (size(src,1)/size(dist,1))); %dst横坐标变换到s…

matlab双线性插值双三次插值对CUFED5进行处理

本文是摘抄与总结&#xff0c;仅供自己学习和日后查阅使用。 可以自己写一个双线性插值函数&#xff0c; ------------------------------------------------------------------- function outputimg my_imresize(A,n) % A 是图像矩阵,n是放缩的倍数 % 返回值outputimg是一…

双三次插值算法的C++实现与SSE指令优化

在上篇文章中&#xff0c;我们讲解了常见的最邻近插值算法、双线性插值算法和双三次插值算法的原理与实现&#xff0c;三种插值算法中双三次插值算法的插值效果最好&#xff0c;但其也是三种算法中计算复杂度最高、耗时最长的算法。本文在给出双三次插值C代码的基础上&#xff…

双三次插值 - 插值图像任意位置亚像素C++

双三次插值 - 插值图像任意位置亚像素C 一、概念 双三次插值又称立方卷积插值。三次卷积插值是一种更加复杂的插值方式。该算法利用待采样点周围16个点的灰度值作三次插值&#xff0c;不仅考虑到4 个直接相邻点的灰度影响&#xff0c;而且考虑到各邻点间灰度值变化率的影响。…

matlab 给图像双三次,图像灰度的双三次插值的MATLAB实现

相比C/C实现&#xff0c;图像灰度的双三次插值的MATLAB实现要方便的多&#xff0c;下面是MATLAB语言实现 clc,clear; ffimread(C:\Program Files\MATLAB\R2013a\bin\work\lena.bmp); [mm,nn]size(ff);%将图像隔行隔列抽取元素&#xff0c;得到缩小的图像f mmm/2;nnn/2; fzeros(…

java 双三次线性插值_三种常见的图像处理双三次插值算法

三种常见的图像处理双三次插值算法 双立方插值计算涉及16像素,间(i’, j’)像中的包括 小数部分的像素坐标。dx表示X方向的小数坐标。dy表示Y方向的小数坐标。 详细 能够看下图: 依据上述图示与双立方插值的数学表达式能够看出。双立方插值本质上图像16个像素点 权重卷积之和…

双三次插值 python实现_Python:用GPU实现双三次插值

它不是GPU(而是尝试利用线程和CPU的向量单元)&#xff0c;但是pyvips比scipy快很多&#xff0c;您可以测试一下。在 我做了个基准&#xff1a;import sys import time import scipy.ndimage import pyvips scale 10 n_loops 10 start time.time() test_image scipy.ndimage…