1、最短路径
1.1 题目描述
万圣节的早上,小Hi和小Ho在经历了一个小时的争论后,终于决定了如何度过这样有意义的一天——他们决定去闯鬼屋!
在鬼屋门口排上了若干小时的队伍之后,刚刚进入鬼屋的小Hi和小Ho都颇饥饿,于是他们决定利用进门前领到的地图,找到一条通往终点的最短路径。
鬼屋中一共有N个地点,分别编号为1…N,这N个地点之间互相有一些道路连通,两个地点之间可能有多条道路连通,但是并不存在一条两端都是同一个地点的道路。那么小Hi和小Ho至少要走多少路程才能够走出鬼屋去吃东西呢?
提示:顺序!顺序才是关键。
输入
每个测试点(输入文件)有且仅有一组测试数据。
在一组测试数据中:
第1行为4个整数N、M、S、T,分别表示鬼屋中地点的个数和道路的条数,入口(也是一个地点)的编号,出口(同样也是一个地点)的编号。
接下来的M行,每行描述一条道路:其中的第i行为三个整数u_i, v_i, length_i,表明在编号为u_i的地点和编号为v_i的地点之间有一条长度为length_i的道路。
对于100%的数据,满足N<=10^3
,M<=10^4
, 1 <= length_i <= 10^3
, 1 <= S, T <= N, 且S不等于T。
对于100%的数据,满足小Hi和小Ho总是有办法从入口通过地图上标注出来的道路到达出口。
输出
对于每组测试数据,输出一个整数Ans,表示那么小Hi和小Ho为了走出鬼屋至少要走的路程。
样例输入
5 23 5 4
1 2 708
2 3 112
3 4 721
4 5 339
5 4 960
1 5 849
2 5 98
1 4 99
2 4 25
2 1 200
3 1 146
3 2 106
1 4 860
4 1 795
5 4 479
5 4 280
3 4 341
1 4 622
4 2 362
2 3 415
4 1 904
2 1 716
2 5 575
样例输出
123
1.2 解答
-
迪杰斯特拉算法是典型的最短路径算法,用来计算一个结点到另一个结点的最短路径。利用BFS的思想,以起始点为中心向外扩展直到终点为止
-
令 S = { 源点src + 已经确定了最短路径的顶点 vi },对任一未收录的顶点 v,定义 dist[v] 为 s 到 v 的最短路径,但该路径仅经过 S 中的顶点。即路径 { s →(vi∈S)→ v } 的最小长度
-
真正的最短路径必须只经过 S 中的顶点
-
每次从未收录的顶点中选一个 dist 最小的收录(贪心)
-
增加一个 v 进入 S,可能影响另一个 w 的 dist 值。dist[w] = min{dist[w], dist[v] + <v, w> 的权重}
举例:如下图所示
- 首先初始化 graph,把所有的距离输入
- 一开始标记起始点,并找出当前 distance 数组中未访问元素的最小值min,记录该值和对应的下标pos。然后,设置这个结点已访问
visited[pos] = true
。 - 再到 graph 中去找该顶点可达的顶点(非MAX且未被访问
!visited[i] && G[pos][i] != INT_MAX
),最后决定是否更新dist[w] = min{dist[w], dist[v] + <v, w> 的权重}
- 由于除去起始点本身,所以我们要循环 N - 1 次
#include<queue>
#define DEBUG
void Dijkstra(vector<vector<int>>& G, vector<bool>& visited, vector<int>& distance, int N, int src) {
for (int i = 1; i <= N; ++i) {
//if (i != src - 1 && graph[src - 1][i] != INT_MAX)
distance[i] = G[src][i];
}
#ifdef DEBUG
cout << "dist : ";
for (auto i : distance) {
if (i == INT_MAX)
cout << setw(5) << "#";
else
cout << setw(5) << i;
}
cout << endl; cout << endl;
cout << endl; cout << endl;
#endif
visited[src] = true;
for (int j = 1; j < N; j++) {
int min = INT_MAX, pos;
for (int i = 1; i <= N; i++) {
if (!visited[i] && distance[i] < min) {
min = distance[i];
pos = i;
}
}
visited[pos] = true;
for (int i = 1; i <= N; i++) {
if (!visited[i] && G[pos][i] != INT_MAX) {
if (distance[i]<