Dijkstra算法是一种用于求解单源最短路径问题的经典算法。它可以在给定有向加权图(无向是特殊的有向)中,从一个起点到其他所有节点的最短路径。
在给定的加权图中,求一个点到其余点的最短路径
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];
- }
堆优化版
可以看到,朴素版有一个遍历找dist最小的操作,如果用小根堆维护dist的话,就可以一下子找到最小了,无需遍历
插入优先队列的知识点
可以使用标准库中的
priority_queue来实现小根堆和大根堆。priority_queue默认实现的是大根堆,如果需要实现小根堆,可以通过自定义比较器来改变默认行为。priority_queue
, greater > minHeap;
- int dijkstra(int b)//求b到各个点的距离
- {
- memset(dist, 0x3f, sizeof dist);
- dist[b] = 0;
-
-
- priority_queue
, cmp> q; - q.push({ b,0 });
-
- while (q.size()) {
- node t = q.top();
- q.pop();
- int ver = t.v, distance = t.w;
- //此时dist[ver] == distance,是最小的
- if (st[ver]) continue;
-
- st[ver] = true;
- for (int i = 0; i < edge[ver].size();i++) {
- //更新ver可以到达的点
- if (dist[i] > edge[ver][i] + distance) {
- dist[i] = edge[ver][i] + distance;
- q.push({ i,dist[i] });
- }
- }
-
- }
-
-
-
-
- if (dist[n] == 0x3f3f3f3f) return -1;
- return dist[n];
- }
邻接表写法


- const int N = 150010;
- typedef pair<int,int> PII;
-
- int h[N],w[N],ne[N],e[N],idx;
- void add(int u,int v,int we){
- w[idx] = we,ne[idx] = h[u],e[idx] = v;
- h[u] = idx++;
- }
- int dist[N];bool st[N];
- int n,m;
- int dijkstra(int b){
- memset(dist,0x3f,sizeof dist);
- dist[b] = 0;
-
- //PII的第一个元素是点x到b点的距离,第二个元素是点x
- priority_queue
,greater> heap; - heap.push({0,b});
- while(heap.size()){
- auto t = heap.top();
- heap.pop();
-
- int ver = t.second,distance = t.first;
- if(st[ver]) continue;
- st[ver] = true;
- //访问ver能到达的点,更新ver到这些点的距离
- for(int i = h[ver];i!=-1;i = ne[i]){
- //切记了,i只是编号!
- int j = e[i];//j才是ver能到达的点
- if(dist[j] > distance + w[i]){
- dist[j] = distance + w[i];
- heap.push({dist[j],j});
- }
-
- }
-
- }
- if(dist[n] == 0x3f3f3f3f) return -1;
- else return dist[n];
-
- }
- void solve() {
- cin>>n>>m;
- memset(h,-1,sizeof h);
- //memset(st,false,sizeof st);
- //idx = 1;
- while(m--){
- int a,b,c;cin>>a>>b>>c;
- add(a,b,c);
- }
- int t = dijkstra(1);
- cout<
-
- }
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
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define inf 0x3f3f3f3f
- #define int long long
- const int N =1010;
- //#include
- typedef long long ll;
- #include
- 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]
- 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
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
-
- #define inf 0x3f3f3f3f
- #define int long long
- const int N =1010;
- //#include
- typedef long long ll;
- #include
- 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;
- }
-
相关阅读:
CLR via C#-托管堆和垃圾回收
架构核心技术之分布式消息队列
Kafka副本选举流程
java 小练习
Java21 + SpringBoot3使用Spring Security时如何在子线程中获取到认证信息
B. The Walkway Codeforces Round 893 (Div. 2)
前端不安装Nginx情况下部署
Android多线程学习:线程池(二)
开源国内镜像站 操作系统、中间件、开发环境
【后端框架】MyBatis(1)
-
原文地址:https://blog.csdn.net/clmm_/article/details/133961313