让我们以洛谷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;
}