标准正权无向图单源最短路,直接从起点 s 跑一次 Dijkstra,输出到终点 t 的距离即可。
OJ: luogu
题目 ID: P1339
难度:普及-
标签:最短路图论堆
日期: 2026-06-20 03:21
题意
给一张带正边权的无向图,要求输出从 s 到 t 的最短路长度。
思路
先看一个最直接的小数据暴力:
cpp
// brute.cpp:Floyd 求任意两点最短路。
// 适合小数据对拍,也能直接帮助理解题意。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 105;
const long long INF = (1LL << 60);
int n, m, s, t;
long long dist_arr[MAXN][MAXN];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m >> s >> t;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i == j) {
dist_arr[i][j] = 0;
}
else {
dist_arr[i][j] = INF;
}
}
}
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
if (w < dist_arr[u][v]) {
dist_arr[u][v] = w;
dist_arr[v][u] = w;
}
}
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (dist_arr[i][k] + dist_arr[k][j] < dist_arr[i][j]) {
dist_arr[i][j] = dist_arr[i][k] + dist_arr[k][j];
}
}
}
}
cout << dist_arr[s][t] << '\n';
return 0;
}暴力做法可以用 Floyd:
- 先求任意两点最短路
- 最后直接输出
dist[s][t]
但这题其实就是最标准的单源最短路模板题。
题目特征很明确:
- 无向图
- 边权都是正数
- 只问一对起点终点
所以直接从 s 出发跑一次 Dijkstra 即可。
记 dist[x] 表示从 s 到 x 的最短路,那么答案就是:
dist[t]
代码
cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2500 + 5;
const int MAXM = 6200 * 2 + 5;
const long long INF = (1LL << 60);
struct Node {
int u;
long long dist;
bool operator < (const Node &other) const {
return dist > other.dist;
}
};
int n, m, s, t;
int head[MAXN], to[MAXM], nxt[MAXM], weight_arr[MAXM], edge_cnt;
long long dist_arr[MAXN];
bool vis[MAXN];
void init_graph() {
edge_cnt = 0;
for (int i = 1; i <= n; i++) {
head[i] = 0;
}
}
void add_edge(int u, int v, int w) {
edge_cnt++;
to[edge_cnt] = v;
weight_arr[edge_cnt] = w;
nxt[edge_cnt] = head[u];
head[u] = edge_cnt;
}
void dijkstra(int start) {
for (int i = 1; i <= n; i++) {
dist_arr[i] = INF;
vis[i] = false;
}
priority_queue<Node> pq;
dist_arr[start] = 0;
pq.push({start, 0});
while (!pq.empty()) {
Node cur = pq.top();
pq.pop();
int u = cur.u;
if (vis[u]) {
continue;
}
vis[u] = true;
for (int i = head[u]; i != 0; i = nxt[i]) {
int v = to[i];
long long nd = dist_arr[u] + weight_arr[i];
if (nd < dist_arr[v]) {
dist_arr[v] = nd;
pq.push({v, nd});
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m >> s >> t;
init_graph();
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
add_edge(u, v, w);
add_edge(v, u, w);
}
dijkstra(s);
cout << dist_arr[t] << '\n';
return 0;
}复杂度
堆优化 Dijkstra 的复杂度:
空间复杂度:
总结
这题没有额外建模,重点就是识别:
- 单源
- 正边权
- 稀疏图
一旦看到这三个信号,基本就应该直接想到堆优化 Dijkstra。