单源最短路径【Dijkstra(堆优化)】【模板】

本文介绍了Dijkstra算法用于求解单源最短路径问题,强调了无负权边时必须使用堆优化,并提供了详细的代码实现。解题过程中,通过初始化起点距离、建立小根堆以及不断更新节点距离来逐步找到最短路径。代码中展示了如何利用优先队列优化Dijkstra算法,提高了效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

>Link

ybtoj单源最短路径

luogu P4779


>解题思路

这道题原本以为是SPFA,结果被卡掉了,所以告诉了我求单源最短路径
#无负权边➡一定要用 d i j dij dij+堆优化(更快)
#有负权边➡一定要用 S P F A SPFA SPFA

D i j k s t r a Dijkstra Dijkstra如何实现?
1.将起点到所有点的距离设为 ∞ ∞ ,但是起点到自己的距离 d i s s t a r t = 0 dis_{start}=0 disstart=0
2.起点已变为白点,剩下的点暂时都为蓝点, d i j dij dij的实现就是将所有的点变为白点
3.以当前的白点 s t a r t start start为起始点,枚举与 s t a r t start start相连的每一条边,进行邻点的更新
4.找出 d i s dis dis最小的蓝点,变其为白点
5.重复循环3、4步骤

堆优化?
我们发现找出 d i s dis dis最小的蓝点这里很花费时间,所以我们可以建立一个小根堆,用 O ( l o g n ) O(logn) O(logn)的时间快速找出 d i s dis dis最小的蓝点

注意: D i j k s t r a Dijkstra Dijkstra不能处理负权边!


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 200010
using namespace std;

struct edge
{
	int to, next, w;
} e[N];
struct node
{
	int dis, pos; //距离,位置
	bool operator <(const node &x) const
	{return x.dis < dis;} //根据dis排的小根堆
	//我也不是很懂,kao网上其他大佬的==
};
std::priority_queue<node> q;
int n, m, S, cnt, h[N], c[N];
bool mark[N];

int main()
{
	int x, y, w;
	scanf ("%d%d%d", &n, &m, &S);
	for (int i = 1; i <= m; i++)
	{
		scanf ("%d%d%d", &x, &y, &w);
		e[++cnt] = (edge){y, h[x], w};
		h[x] = cnt;
	}
	memset (c, 0x7f, sizeof (c));
	c[S] = 0;
	q.push ((node){0, S});
	while (!q.empty())
	{
		node u = q.top();
		q.pop();
		if (mark[u.pos]) continue;
		mark[u.pos] = 1; //mark标记是否以当前点作为白点向周围扩散过
		for (int i = h[u.pos]; i; i = e[i].next)
		{
			int v = e[i].to;
			if (c[v] > c[u.pos] + e[i].w)
			{
				c[v] = c[u.pos] + e[i].w;
				if (!mark[v]) q.push((node){c[v], v}); //如果没有扩散过就放进来
			}
		}
	}
	for (int i = 1; i <= n; i++)
	  printf ("%d ", c[i]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值