当前位置: 首页 > article >正文

Dijkstra算法基础详解,附有练习题

介绍

Dijkstra算法是一种用于求解单源最短路径问题的经典算法。它可以在给定有向加权图(无向是特殊的有向)中,从一个起点到其他所有节点的最短路径。

作用:

在给定的加权图中,求一个点到其余点的最短路径

基本思想:

  • 初始化一个距离数组dist[],表示起点到各个节点的当前最短距离,初始时起点的最短距离为0,其余节点的最短距离为无穷大。
  • 创建一个集合S,用于存放已经确定最短路径的节点,初始时集合S为空。
  • 重复以下步骤,直到集合S包含了所有节点:
    • 在未确定最短路径的节点中,选择一个节点v,选择的是dist[v]值最小,将该节点加入集合S。
    • 更新节点v的所有邻接节点u的最短距离,如果通过节点v到达节点u的距离比当前最短路径更短,则更新最短距离dist[u]为新的最短距离。
    • 表示为: dist[u] = min(dist[u],dist[v]+edge[v][u])

Dijkstra算法的关键是如何选择节点v,这里使用了贪心策略,每次选择距离起点最近的未确定最短路径的节点,确保每次加入的节点都是当前最短距离确定的。

模板如下:

int dijkstra(int b)//求b到各个点的距离
{
	memset(dist, 0x3f, sizeof dist);
	dist[b] = 0;

	for (int i = 0; i < n - 1; i++)
	{
		int t = -1;     // 在还未确定最短路的点中,寻找距离最小的点
		for (int j = 1; j <= n; j++)
			if (!st[j] && (t == -1 || dist[t] > dist[j]))
				t = j;

		//从t这个点更新到其他点的距离。
		//虽然是遍历了每个点,但并不代表t可以到任意点,
		//因为会把到不了的边的距离设为inf,就避免了考虑t点可以到哪些点的问题
		for (int j = 1; j <= n; j++)
			dist[j] = min(dist[j], dist[t] + v[t][j]);

		st[t] = true;
	}

	if (dist[n] == 0x3f3f3f3f) return -1;
	return dist[n];
}

Dijkstra序列

输入样例:
5 7
1 2 2
1 5 1
2 3 1
2 4 1
2 5 2
3 5 1
3 4 1
4
5 1 3 4 2
5 3 1 2 4
2 3 4 5 1
3 2 1 5 4
输出样例:
Yes
Yes
Yes
No

分析:还是要先弄目标dijkstra序列的含义是什么,这个困扰我了很久。

我们知道,在构建dist数组时,每次是选 还没有选过当前dist最小 的点,在这个点的基础上进行更新。然后要选n次,我们这n次选的点的序列就称作dijkstra序列(第一个点就是起点)。

例如:5,1,3,4,2。代表点5是起点,然后选点1,点3,点4,点2。

设每次选的点为dist[i],那么dist[i]一定小于当前所有还没选过的点。以这个为判断条件,如果不满足,则不是一个dijkstra序列。

#include<assert.h>
#include<cstdio>
#include<set>
#include<list>
#include<queue>
#include<math.h>
#include<stdlib.h>
#include<string>
#include<string.h>
#include <stdio.h>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<sstream>
#include<stack>
#include <utility>
#include<map>
#include <vector>

#define inf 0x3f3f3f3f
#define int long long
const int N =1010;
//#include <bits/stdc++.h>
typedef long long ll;
#include<iostream>
using namespace std;

//long long MAX(long long a, long long b) { return a < b ? b : a; }

int n, m;


int v[N][N];//存每条边,v[i][j]代表i到j的距离。如果i到j没有直接的路径,那么设为inf
int dist[N];//存i号点到各个点的最短距离
int st[N];//存到达该点该点是否已经确定最短路径
int q[N];

int dijkstra() {//从b开始,到各个点的距离
	memset(dist, inf, sizeof(dist));
	memset(st, 0, sizeof(st));
	dist[q[0]] = 0;//到达自己的距离是0

	
	for (int i = 0; i < n; i++) {

		int cur = q[i];
		for (int j = 1; j <= n; j++) {
			if (!st[j] && dist[j]<dist[cur]) {
				return false;
			}
		}

		//从cur这个点更新到其他点的距离。
		//虽然是遍历了每个点,但并不代表cur可以到任意点,
		//因为会把到不了的边的距离设为inf,就避免了考虑cur点可以到哪些点的问题
		for (int j = 1; j <= n; j++) {
			dist[j] = min(dist[j], dist[cur] + v[cur][j]);
		}

		st[cur] = 1;
	}

	return 1;
}
signed main() {
	cin >> n >> m;
	memset(v, inf, sizeof(v));

	for (int i = 0; i < m; i++) {
		int a, b, d; cin >> a >> b >> d;

		//因为是无向图
		v[a][b] = d;
		v[b][a] = d;
	}
	int k; cin >> k;
	while (k--) {
		vector<int> t;
		t.push_back(0);
		for (int i = 0; i < n; i++) {
			cin >> q[i];
		}
		if (dijkstra()) cout << "Yes" << endl;
		else cout << "No" << endl;

	}

	return 0;
}

奶牛回家

输入样例:
5
A d 6
B d 3
C e 9
d Z 8
e Z 3
输出样例:
B 11

分析:简单题。命名为大写字母的牧场才有牛,可以逆向思考,从牛棚Z开始往这些牧场走,那条路最短。

易错点,两个牧场间可能有多条路,这些路长度可能不一样,注意判断。

#include<cstdio>
#include<set>
#include<list>
#include<queue>
#include<math.h>
#include<stdlib.h>
#include<string>
#include<string.h>
#include <stdio.h>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<sstream>
#include<stack>
#include <utility>
#include<map>
#include <vector>

#define inf 0x3f3f3f3f
#define int long long
const int N =1010;
//#include <bits/stdc++.h>
typedef long long ll;
#include<iostream>
using namespace std;

//long long MAX(long long a, long long b) { return a < b ? b : a; }

int n;

int v[N][N];  // 存储每条边
int dist[N];  // 存储1号点到每个点的最短距离
bool st[N];   // 存储每个点的最短路是否已经确定

int get(char x) {
	if (x >= 'A' && x <= 'Z') return x - 'A' + 1;
	return x - 'a' + 26 + 1;

}
void dijkstra() {
	memset(dist, inf, sizeof(dist));
	memset(st, 0, sizeof(st));
	dist[26] = 0;//Z到Z距离是0
	for (int i = 1; i <= 52; i++) {
		int cur = -1;
		for (int j = 1; j <= 52; j++) {
			if (!st[j] && (cur == -1 || dist[cur] > dist[j])) {
				cur = j;
			}
		}

		for (int j = 1; j <= 52; j++) {
			dist[j] = min(dist[j], dist[cur] + v[cur][j]);
		}
		st[cur] = 1;
	}

}
signed main() {
	cin >> n;
	memset(v, inf, sizeof(v));
	while (n--) {
		char a, b; int c;
		cin >> a >> b >> c;
		int d = get(a);
		int e = get(b);
		v[d][e] = v[e][d] = min(v[d][e], c);

	}
	dijkstra();
	int index = 0, len = inf;
	for (int i = 1; i <= 25; i++) {
		if (len > dist[i] && dist[i] <= 10000 * 1000) {
                           //如果大于这个距离就是没有到i的路,距离为inf
			len = dist[i];
			index = i;
		}
	}
	printf("%c %lld", index + 'A' - 1, len);

	return 0;
}


http://www.kler.cn/a/107325.html

相关文章:

  • 使用Python实现对接Hadoop集群(通过Hive)并提供API接口
  • 用MVVM设计模式提升WPF开发体验:分层架构与绑定实例解析
  • git配置远程仓库的认证信息
  • Ruby编程语言全景解析:从基础到进阶
  • win32 / WTL 开发多线程应用,子线程传递大对象给UI线程(主窗口)的方法
  • 万字长文解读深度学习——ViT、ViLT、DiT
  • OpenAI大模型项目计划表(InsCode AI 创作助手)
  • Android Studio 查看Framework源码
  • 基于LCC的Buck谐振变换器研究
  • arcgis js api FeatureLayer加载时返回数据带*问题
  • 针对多分类问题,使用深度学习--Keras进行微调提升性能
  • MySQL数据库#6
  • Redis 主从复制和哨兵监控,实现Redis高可用配置
  • 革新技术,释放创意 :Luminar NeoforMac/win超强AI图像编辑器
  • 浅谈UI自动化测试
  • KDChart3.0编译过程-使用QT5.15及QT6.x编译
  • 深度学习——图像分类(CIFAR-10)
  • Centos系统使用yum安装Java jdk
  • OpenCV学习(一)——图像读取
  • Mysql 数据库
  • 数据分析和互联网医院小程序:提高医疗决策的准确性和效率
  • 网络协议--TCP:传输控制协议
  • 「网络编程」数据链路层协议_ 以太网协议学习
  • LeetCode 1465. 切割后面积最大的蛋糕
  • Elasticsearch7.8.1集群安装手册
  • vscode 保存 “index.tsx“失败: 权限不足。选择 “以超级用户身份重试“ 以超级用户身份重试。