单源最短路径 1. 狄克斯特拉(Dijkstra)算法

狄克斯特拉(Dijkstra)算法

单源最短路径问题

给定一张有向图\(G=(V,E)\)\(V\)是点集,\(E\)是边集,\(|V|=n\)\(|E|=m\),节点以\([1,n]\)之间的连续整数编号,\((x,y,z)\)描述一条从\(x\)出发,到达\(y\),权值为\(z\)的有向边,求长度为\(n\)的数组\(dist\),其中\(dist[i]\)表示从起点\(s\)到节点\(i\)的最短路径的长度。
——选自李煜东《算法竞赛进阶指南》

理论知识部分

Dijkstra算法基于贪心思想:在寻找最短路时,先找每两个节点间的最短路,再依次扩大范围,直到求出\(dist\)数组。

步骤

1.初始化\(dist\)数组(0x3f3f3f3f),\(d[s]=0\)\(v\)数组初始化为\(false\)
2.找到\(dist[i]\)值最小且未被访问过的节点\(i\),标记已访问
3.扫描节点\(i\)的每一条出边(终点用\(to\)表示,权值用\(w\)表示),如果\(d[to] > d[i] + w\),则\(d[to]=d[i]+w\)
4.重复\(2\)~\(3\)步,直到所有节点都被访问过

代码实现部分

图的存储

参见这篇博客

算法主体

步骤\(2\)\(dist\)值最小节点\(i\)可以用STL priority_queue实现,因为它是大根堆,又要表现\(dist\)值最小和节点编号\(i\),两个信息,所以可以用它存储一个二元组,第一元为\(-dist[i]\)(实现小根堆),第二元为节点编号\(i\)

priority_queue < pair<int,int> > q;

void dis(void)
{
	memset(d,0x3f,sizeof(d));
	d[s] = 0;
	q.push( make_pair(0,s) );
	while(q.size())
	{
		int x = q.top().second;//获取节点编号
		q.pop();
		if(vis[x])//是否被访问
			continue;
		vis[x] = 1;//标记已访问
		for(int i = head[x],y ;i ;i = Next[i])//步骤3
		{
			y = edge[i];
			if(d[y] > d[x] + weight[i])
			{
				d[y] = d[x] + weight[i];
				q.push( make_pair(-d[y],y) );//下一个节点
			}
		}
	}
	for(int i = 1 ;i <= n ;i++)
            cout << d[i] << ' ';//输出结果
}

总结

虽然本篇博客比较短,但该算法在图论中有重要地位,它也有着众多优化和变形。
请读者思考本算法的各种实现细节。

posted @ 2025-03-06 19:20  Kelojonle  阅读(24)  评论(0)    收藏  举报