题目地址:
https://www.acwing.com/problem/content/851/
给定一个 n n n个点 m m m条边的有向图,可能存在重边和自环,无负权边。求 1 1 1号点到 n n n号点的最短距离。如果不存在路径,则输出 − 1 -1 −1。
输入格式:
第一行包含整数
n
n
n和
m
m
m。接下来
m
m
m行每行包含三个整数
x
x
x,
y
y
y,
z
z
z,表示存在一条从点
x
x
x到点
y
y
y的有向边,边长为
z
z
z。
输出格式:
输出一个整数,表示
1
1
1号点到
n
n
n号点的最短距离。如果路径不存在,则输出
−
1
-1
−1。
数据范围:
1
≤
n
≤
500
1\le n\le 500
1≤n≤500
1
≤
m
≤
1
0
5
1\le m\le 10^5
1≤m≤105
e
≤
10000
e\le 10000
e≤10000
e
e
e为边长
由数据范围知道这个图是个稠密图,所以要用朴素版Dijkstra算法来做(意思是,求距离源点最近的点的时候,要用循环的方式找到)。具体算法是这样的,首先开两个数组,一个int数组存各个点到 1 1 1号点的最短距离,另一个bool数组存 1 1 1号点到各个点的最短路是否已经被求出。显然 1 1 1号点自己的最短路是 0 0 0,已经求出了(注意,即使它的最短路确实已经确定了,但是这个时候不要标记其最短路已经求出,因为我们还要靠它来更新其余点最短路距离。具体看代码),接下来进行 n n n次循环,每次新求出某个点到 1 1 1号点的最短路。在每次循环里,首先找到未确定最短路的点中,最短路最短的那个点(第一轮循环会找到源点。这就是为什么一开始不要标记源点为已求出),然后标记其为已求出,再用它以及它到各个点的距离(这个距离存在邻接矩阵里了),来更新所有未求出最短路的点。这样每次循环都能求出一个点的最短路,循环 n n n次就求出来源点到所有点的最短路了。当然中途如果提前求出了第 n n n号点的最短路,可以直接退出循环。代码如下:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 510, INF = 0x3f3f3f3f;
int n, m;
int g[N][N], dist[N];
bool st[N];
int dijkstra() {
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for (int i = 0; i < n; i++) {
int t = -1;
for (int j = 1; j <= n; j++)
if (!st[j] && (t == -1 || dist[t] > dist[j])) t = j;
if (t == n) break;
st[t] = true;
for (int j = 1; j <= n; j++)
if (!st[j]) dist[j] = min(dist[j], dist[t] + g[t][j]);
}
return dist[n] == INF ? -1 : dist[n];
}
int main() {
cin >> n >> m;
memset(g, 0x3f, sizeof g);
while (m--) {
int a, b, c;
cin >> a >> b >> c;
if (a == b) g[a][b] = 0;
else g[a][b] = min(g[a][b], c);
}
cout << dijkstra() << endl;
}
时空复杂度 O ( n 2 ) O(n^2) O(n2)。