Dijkstra朴素版+堆优化版例题简单讲解

让我们以洛谷P3371的一道Dijkstra模板题开始吧!

【模板】单源最短路径(弱化版) - 洛谷

题目背景

本题测试数据为随机数据,在考试中可能会出现构造数据让SPFA不通过,如有需要请移步 P4779

题目描述

如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度。

输入格式

第一行包含三个整数 n,m,s,分别表示点的个数、有向边的个数、出发点的编号。

接下来 m 行每行包含三个整数 u,v,w,表示一条 u→v 的,长度为 w 的边。

输出格式

输出一行 n 个整数,第 i 个表示 s 到第 i 个点的最短路径,若不能到达则输出 2^31−1。

输入输出样例

输入 1

4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4

输出 1

0 2 4 3

Tips:

        邻接矩阵存图适用于稠密图。

        一开始用邻接矩阵写的朴素dijkstra,结果MLE了。所以,我觉得能用链式前向星(邻接表)存图就不要用邻接矩阵,邻接矩阵O(n^2)复杂度太高啦!

        下面是AC代码:

解法1:(链式前向星存图的朴素dijkstra版)

#include<bits/stdc++.h>
using namespace std;

const int MAXV = 2147483647;
const int N = 500020;
long long dist[N];
bool st[N];
int n, m, s;
int u, v, w;

//建立邻接表 
int head[N], nxt[N], to[N], we[N], idx = 0;

//插入数据以存图
void add(int x, int y, int z) {
	to[idx] = y;
	we[idx] = z;
	nxt[idx] = head[x];
	head[x] = idx++;
}

void dijkstra(int start) {
	fill(dist, dist + N, MAXV);
	dist[start] = 0;
	for (int i = 0; i < n; i++) {
		int t = -1;  //存储当前访问过的点
		for (int j = 1; j <= n; j++) {
			if (!st[j] and (t == -1 or dist[t] > dist[j]))
				t = j;
		}
		st[t] = true;
		for (int k = head[t]; k != -1; k = nxt[k]) {
			int j = to[k];
			dist[j] = min(dist[j], dist[t] + we[k]);
		}
	}

}

int main() {
	cin >> n >> m >> s;
	fill(head, head + N, -1);
	for (int i = 0; i < m; i++) {
		cin >> u >> v >> w;
		add(u, v, w);
	}
	dijkstra(s);
	for (int i = 1; i <= n; i++) {
		cout << dist[i] << " ";
	}

	return 0;
}

解法2:(链式前向星存图+堆优化版)

#include<bits/stdc++.h>
using namespace std;

const int MAXV = 2147483647;
const int N = 550000;
int n, m, s;
int x, y, z;
bool st[N];
int dist[N];

//定义一个邻接表来存图
int head[N], to[N], ne[N], w[N];
int idx = 0;

typedef pair<int, int> PII;

void add(int x, int y, int z) {
	w[idx] = z;
	to[idx] = y;
	ne[idx] = head[x];
	head[x] = idx++;
}

void dijkstra() {
	fill(dist, dist + N, MAXV);
	dist[s] = 0;
	priority_queue<PII, vector<PII>, greater<PII> > heap;  //定义一个小根堆
	heap.push({ 0,s });
	while (heap.size()) {
		PII k = heap.top();  //先取距离最短的点
		heap.pop();
		int ver = k.second, distance = k.first;
		if (st[ver]) continue;
		st[ver] = true;
		for (int i = head[ver]; i != -1; i = ne[i]) { //搜索堆顶所有连边
			int j = to[i];
			if (dist[j] > distance + w[i]) {
				dist[j] = distance + w[i];
				heap.push({ dist[j], j });
			}
		}
	}
}

int main() {
	fill(head, head + N, -1);
	cin >> n >> m >> s;
	while (m--) {
		cin >> x >> y >> z;
		add(x, y, z);
	}
	dijkstra();
		for (int i = 1; i <= n; i++) {
			cout << dist[i] << " ";
		}

	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值