题目背景
2018 年 7 月 19 日,某位同学在 NOI Day 1 T1 归程 一题里非常熟练地使用了一个广为人知的算法求最短路。
然后呢?
100 → 60;
Ag → Cu
最终,他因此没能与理想的大学达成契约。
小 F 衷心祝愿大家不再重蹈覆辙。
题目描述
给定一个 个点, 条有向边的带非负权图,请你计算从 出发,到每个点的距离。
数据保证你能从 出发到任意点。
输入格式
第一行为三个正整数 。 第二行起 行,每行三个非负整数 ,表示从 到 有一条权值为 的有向边。
输出格式
输出一行 nn 个空格分隔的非负整数,表示 ss 到每个点的距离。
输入输出样例
输入
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
输出
0 2 4 3
思路
用优先队列优化的dijkstra算法,用Node来存每个点,并用vis来记录是否访问,边则用链式前向星来记录。
实现代码
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 1e5 + 5;
const int maxm = 2e5 + 5;
const int Inf = 0x3f3f3f3f;
struct Edge { //边
int next,to, val;
Edge() {}
Edge(int n, int t, int v): next(n), to(t), val(v) {}
}edge[maxm];
struct Node { // dijkstra 算法中用于优先队列中的点结构体
int no, dis;
Node(int n, int d) : no(n), dis(d) {}
bool operator < (const Node& other) const { //因为是优先队列,所以重载 <
return dis > other.dis;
}
};
int dis[maxn];
int vis[maxn];
int head[maxn];
int cnt = 0;
void link(int u, int v, int w) { // 链式前向星的更新
edge[++cnt] = Edge(head[u], v, w);
head[u] = cnt;
}
void dijkstra(int s, int n) { //从 s 点 开始 调用
priority_queue<Node> q;
memset(dis, Inf, sizeof(dis));
memset(vis, 0, sizeof(vis));
q.push(Node(s, 0));
while (q.size()) {
Node top = q.top(); q.pop();
if (vis[top.no]) continue;
dis[top.no] = top.dis, vis[top.no] = 1;
for (int i = head[top.no]; i; i = edge[i].next) {
int to = edge[i].to, d = edge[i].val;
if (vis[to]) continue;
q.push(Node(to, dis[top.no] + d));
}
}
for (int i = 1; i <= n; i++) {
if (i != 1) cout << " ";
cout << dis[i];
}
cout << endl;
}
int main() {
memset(head, 0., sizeof(head));
int n, m, s, u, v, w;
cin >> n >> m >> s;
for (int i = 1; i <= m; i++) {
cin >> u >> v >> w;
link(u, v, w);
}
dijkstra(1, n);
return 0;
}