首页 > 编程语言 >迪克斯特拉算法:单源最短路径问题

迪克斯特拉算法:单源最短路径问题

时间:2024-12-07 20:31:59浏览次数:5  
标签:路径 dist int graph printf 单源 斯特拉 迪克 节点

一、迪杰斯特拉算法的介绍

迪杰斯特拉(Dijkstra)算法是一种用于计算加权图中单源最短路径的经典算法,由荷兰计算机科学家艾兹赫·迪杰斯特拉(Edsger Dijkstra)于1956年提出。迪杰斯特拉算法的核心思想是通过贪心策略,不断选择当前路径代价最小的节点,并逐步扩展搜索范围,直到找到从源节点到所有可达节点的最短路径。它适用于非负权重的加权图,不能处理负权重。

二、单源最短路径问题的介绍

1.介绍

给定一个带权有向图G=(V,E),其中每条边的权是一个实数。另外,还给定V中的一个顶点,称为源。现在要计算从源到其他所有各顶点的最短路径长度。这里的长度就是指路上各边权之和,这个问题通常称为单源最短路径问题。该问题的经典求解方法为迪克斯特拉算法,该算法基于贪心法进行设计,能够有效求解单源最短路径问题。

2.举例

下面这个图片是对单源最短路径进行解释

由这个图片可以看到,由a开始,分别向b,c,d e,f四个顶点进行遍历,查找分别到四个顶点中的最短路径的问题

下面利用迪克斯特拉算法来进行解释:

第一次第二次第三次第四次第五次
b

2

(a,b)

c

5

(a,c)

d
e
f
终点集{a,b}

由a开始有两个顶点可以到达,分别是b和c,他们的权重为2和5,其他三个点都无法到达,则把他们表示为无穷。

第一次第二次第三次第四次第五次
b

2

(a,b)

c

5

(a,c)

3

(a,b,c)

d

5

(a,b,d)

e
f
终点集{a,b}{a,b,c}

由图表可知,得到b开始,可到达c与d,权重分别为3和5,e和f则无法到达。

第一次第二次第三次第四次第五次
b

2

(a,b)

c

5

(a,c)

3

(a,b,c)

d

5

(a,b,d)

5

(a,b,d)

e

7

(a,b,c,e)

f

4

(a,b,c,f)

终点集{a,b}{a,b,c}{a,b,c,f}

由c出发,开始向e和f,权重分别为7和4。

第一次第二次第三次第四次第五次
b

2

(a,b)

c

5

(a,c)

3

(a,b,c)

d

5

(a,b,d)

5

(a,b,d)

5

(a,b,d)

e

7

(a,b,c,e)

7

(a,b,c,e)

6

(a,b,d,e)

f

4

(a,b,c,f)

终点集{a,b}{a,b,c}{a,b,c,f}{a,b,c,f,d}{a,b,c,f,d,e}

由上面的三次可以知道最后的两次遍历情况。

三、算法的代码编写

1.图的表示

 代码使用邻接矩阵来表示图,其中 adjMatrix[i][j] 表示从节点 i 到节点 j 的边的权重。

如果两个节点之间没有直接的边,则初始化为 INT_MAX(无穷大)

#include <stdio.h>
#include <limits.h>
#define MAX_VERTICES 100
struct Graph {
	int numVertices;
	int numEdges;
    int adjMatrix[MAX_VERTICES][MAX_VERTICES]; // 邻接矩阵
};
void inputGraph(struct Graph* graph) {
	printf("输入顶点数:");
	scanf("%d", &graph->numVertices);
	printf("输入边数:");
	scanf("%d", &graph->numEdges);
	// 初始化邻接矩阵为无穷大
	
	for (int i = 0; i < graph->numVertices; i++) {
	    for (int j = 0; j < graph->numVertices; j++) {
	        graph->adjMatrix[i][j] = (i == j) ? 0 : INT_MAX; 
	    }
	}

	int u, v, w;
	for (int i = 0; i < graph->numEdges; i++) {
	    printf("输入边 u, v, w(例如:0 1 5 表示从顶点0到顶点1的边权重为5):");
	    scanf("%d %d %d", &u, &v, &w);
	    graph->adjMatrix[u][v] = w; 
	    
	}
}

2.迪克斯特拉算法的实现

(1)、初始化:dist 数组记录从源节点到每个节点的最短距离,初始时 dist[startVertex] = 0,其他节点 dist[i] = INT_MAXvisited 数组标记节点是否被访问过,初始时所有节点都未被访问(visited[i] = 0)。prev 数组记录从源节点到每个节点的前驱节点,初始时 prev[i] = -1

(2)、选择当前最短路径的节点:在每一轮迭代中,从未访问的节点中选择 dist[v] 最小的节点 u 进行扩展。

(3)、更新邻居节点的最短路径:遍历 u 的所有邻居节点 v,如果通过 u 到 v 的路径比当前记录的 dist[v] 更短,则更新 dist[v] 和 prev[v]

void Dijkstra(struct Graph* graph, int startVertex) {
	int dist[MAX_VERTICES]; // 距离数组
    int visited[MAX_VERTICES] = {0}; // 访问数组
	int prev[MAX_VERTICES]; // 顶点数组
	for (int i = 0; i < graph->numVertices; i++) {
	    dist[i] = INT_MAX;
	    prev[i] = -1;
	}
	dist[startVertex] = 0; // 起点到自身的距离为0
	
	for (int count = 0; count < graph->numVertices - 1; count++) {
	    int u = -1; // 距离最小的顶点
	    int minDist = INT_MAX;
	    for (int v = 0; v < graph->numVertices; v++) {
	        if (!visited[v] && dist[v] < minDist) {
	            minDist = dist[v];
	            u = v;
	        }
	    }
	    visited[u] = 1;
	    for (int v = 0; v < graph->numVertices; v++) {
	        if (graph->adjMatrix[u][v] != INT_MAX && !visited[v] && dist[u] + graph->adjMatrix[u][v] < dist[v]) {
	            dist[v] = dist[u] + graph->adjMatrix[u][v];
	            prev[v] = u;
	        }
	    }
	}
	// 打印结果
	printf("从顶点 %d 到其他顶点的最短距离:\n", startVertex);
	for (int i = 0; i < graph->numVertices; i++) {
	    if (dist[i] == INT_MAX) {
	        printf("到顶点 %d 不可达\n", i);
	    } else {
	        printf("到顶点 %d 的距离为 %d\n", i, dist[i]);
	        printf("路径:");
	        int current = i;
	        while (current != -1) {
	            printf("%d ", current);
	            current = prev[current];
	        }
	        printf("\n");
	        
	    }
	}
}

3.路径输出

 printf("到顶点 %d 的距离为 %d\n", i, dist[i]);
	        printf("路径:");
	        int current = i;
	        while (current != -1) {
	            printf("%d ", current);
	            current = prev[current];
	        }
	        printf("\n");
	        

4.输入验证:

int main() {
	struct Graph graph;
	inputGraph(&graph);
	int startVertex;
	printf("输入起点顶点(从0开始编号):");
	scanf("%d", &startVertex);
	// 验证起点是否在图的顶点范围内
	if (startVertex < 0 || startVertex >= graph.numVertices) {
	    printf("起点顶点编号无效!\n");
	    return 1;
	}
	Dijkstra(&graph, startVertex);
	return 0;
	}

四、单源最短路径问题的应用场

地图导航与路径规划:介绍迪克斯特拉算法在地图导航中的应用,计算从起点到终点的最短路径。

网络路由与数据转发:说明迪克斯特拉算法在计算机网络中的应用,计算最优传输路径。

物流与供应链管理:阐述迪克斯特拉算法在物流管理中的应用,优化运输路线,降低运输成本。

机器人导航与路径规划:介绍迪克斯特拉算法在机器人导航中的应用,计算机器人从起点到终点的最短路径。

标签:路径,dist,int,graph,printf,单源,斯特拉,迪克,节点
From: https://blog.csdn.net/2303_79258468/article/details/144315429

相关文章

  • 【图论】单源最短路径 Dijkstra
    单源出发,最短路径,松弛。Dijkstra算法是所有最短路径算法中某种意义上最快的,只是代码略为难写。松弛Dijkstra算法的精髓,就是两个字:松弛。包括所有的最短路径算法,都依靠的是这个词。何为松弛?假设现有若干个点,点\(v\)到起点的最短路径很大,但是有另一个点\(u\),它的路径值较......
  • 3、贪心算法python(活动选择问题、单源最短路径)
    一、活动选择问题给定一组活动,每个活动都有一个开始时间和结束时间,要求选择尽可能多的活动,并且这些活动之间不能有重叠。贪心策略的核心思想是每次选择结束时间最早的活动,这样可以为后续的活动留出更多的时间空间。活动选择问题的贪心算法步骤1、排序:首先按活动的结束时间对......
  • NOI提高级 图论算法:单源次短路
    DIJ(单源次短路)-TwoPaths-HDU6181DIJ(单源次短路)-TwoPaths-HDU6181-CSDN博客单源次短路(P2829大逃离)单源次短路(P2829大逃离)-CSDN博客单源次短路算法学习笔记单源次短路算法学习笔记-Wiueh_Plus-博客园次短路及次短路计数次短路及次短路......
  • 论文分享---CVPR2024:用于单源域泛化目标检测的无偏 Faster R-CNN
     论文地址https://arxiv.org/pdf/2405.15225简介:此论文由刘亚静,周世军,刘希尧,郝春辉,范宝杰,田建东,中国科学院沈阳自动化研究所机器人国家重点实验室、中国科学院机器人与智能制造研究所、中国科学院大学、南京邮电大学在CVPR2024上发表。摘要单源域泛化(SDG)物体检测是一项......
  • 图论篇--代码随想录算法训练营第五十九天打卡|Bellman_ford 算法精讲,SPFA算法,Bellman
    本系列算法用来解决有负权边的情况Bellman_ford算法精讲题目链接:94.城市间货物运输I题目描述:某国为促进城市间经济交流,决定对货物运输提供补贴。共有n个编号为1到n的城市,通过道路网络连接,网络中的道路仅允许从某个城市单向通行到另一个城市,不能反向通行。网络......
  • 信息学奥赛初赛天天练-86-NOIP2014普及组-基础题5-球盒问题、枚举算法、单源最短路、D
    1NOIP2014普及组基础题521把M个同样的球放到N个同样的袋子里,允许有的袋子空着不放,问共有多少种不同的放置方法?(用K表示)()例如,M=7,N=3时,K=8;在这里认为(5,1,1)和(1,5,1)是同一种放置方法。问:M=8,N=5时,K=()22如图所示,图中每条边上的数字表示该边的长度,则从......
  • 信息学奥赛初赛天天练-86-NOIP2014普及组-基础题5-球盒问题、枚举算法、单源最短路、D
    信息学奥赛初赛天天练-86-NOIP2014普及组-基础题5-球盒问题、枚举算法、单源最短路、Dijkstra算法、Bellman-Ford算法PDF文档公众号回复关键字:202409081NOIP2014普及组基础题521把M个同样的球放到N个同样的袋子里,允许有的袋子空着不放,问共有多少种不同的放置方法?(......
  • Bellmanford与Spfa解决存在负边权的单源汇最短路问题
    上个文章讲了Dijkstra算法但是Dijkstra算法只能解决单源汇非负边权的最短路问题这次文章来讲单源汇存在负边权的解决方法Bellmanforda和spfa算法二者适用场景区别:一般来说使用spfa就能解决大部分的问题,但问题出现不超过k条边的时候应当使用Bellmanford算法BellmanFord:随意存......
  • 迪杰斯特拉(Dijkstra)算法(C/C++)
    迪杰斯特拉(Dijkstra)算法是一种用于在加权图中找到单个源点到所有其他顶点的最短路径的算法。它是由荷兰计算机科学家艾兹格·迪科斯彻(EdsgerDijkstra)在1956年提出的。Dijkstra算法适用于处理带有非负权重的图。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法,每次遍历到始......
  • 代码随想录算法训练营第61天 | 图论part08:拓扑排序+迪杰斯特拉朴素法
    117.软件构建https://kamacoder.com/problempage.php?pid=1191拓扑排序精讲https://www.programmercarl.com/kamacoder/0117.软件构建.html#拓扑排序的背景47.参加科学大会https://kamacoder.com/problempage.php?pid=1047dijkstra(朴素版)精讲https://www.programmercarl.c......