刷题笔记56—最短路径(Dijkstra)、最小生成树(Prim、Kruskal)


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^3M<=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
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值