前言:

今日温习了前段时间学习的Dijkstra算法我在复习这个算法的时候,常常因为没有初始化或者条件判断而错误。

现在让我来浅谈一下我对该算法的理解

概述:

该算法常常应用在处理单源最短路问题,具体的数学证明以及原理可以查百度。

大致是通过不断迭代找到当前最短路径,再通过该最短路径往后延伸,找到到终点的最短路径。

常见的Dijkstra算法分为朴素版以及堆优化版,前者的时间复杂度为O(N*N),后者的时间复杂度为O(MlogN),其中N为点的个数,M为边的个数

朴素版用来处理稠密图,稠密图用邻接矩阵存储图,堆优化版用来处理稀疏图,稀疏图用邻接表存储图。

实践

题目:租用游艇

长江游艇俱乐部在长江上设置了 n 个游艇出租站 1,2,……,n。游客可在这些游艇出租站租用游艇,并

在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为 r(i,j)(1<=i<=j)。

试设计一个算法,计算出从游艇出租站1到游艇出租站n所需的最少租金。

解法一:朴素版Dijkstra

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int g[N][N],dist[N];//g[N][N]表示相邻两点的距离,dist[N]表示从起点到某一点的最短路径
bool st[N];//st[N]表示该点是否被利用找过最短路径
int n;
int dijkstra(){
memset(dist,0x3f,sizeof dist);//初始化数组
dist[1]=0;//特殊情况特殊考虑
for(int i=0;i<=n-1;i++){//进行n-1次迭代找到最小路径
int t=-1;//为每一次迭代的初始点提供便利
for(int j=1;j<=n;j++){
if(!st[j]&&(t==-1||dist[t]>dist[j])){
t=j;//该点既要没被利用过同时也是目前的最短路径
}
}
for(int j=1;j<=n;j++){
dist[j]=min(dist[j],dist[t]+g[t][j]);//利用更新的点找最短路径
}
st[t]=true;//标记该点已被利用过
}
return dist[n];
}
int main(){
cin>>n;
memset(g,0x3f,sizeof g);
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
cin>>g[i][j];
}
}
cout<< dijkstra();
return 0;
}

解法二: 堆优化版Dijkstra

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=1005;
bool st[N];
int a[N][N];
int w[N],h[N],ne[N],e[N],idx;//构建邻接表
int n,dist[N];
void add(int x,int y,int c){//连接边
w[idx]=c;
e[idx]=y;
ne[idx]=h[x];
h[x]=idx++;
}
int dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[1]=0;
priority_queue<PII,vector<PII>,greater<PII>>heap;//建立小顶堆,优先对第一个元素从小到大排序,其次才是第二个元素
heap.emplace(0,1);
while(heap.size()){
auto t=heap.top();//不断利用该当前最小路径点,找到最终最小路径
heap.pop();//利用过后排出
int ver=t.second,val=t.first;
if(st[ver])continue;
st[ver]=true;//将利用过的点打上标记
for(int i=h[ver];i!=-1;i=ne[i]){//利用该点更新最短路径
int j=e[i];
if(dist[j]>val+w[i]){
dist[j]=val+w[i];
heap.emplace(dist[j],j);
}
}
}
return dist[n];
}
int main(){
memset(a,0x3f,sizeof a);
memset(h,-1,sizeof h);
cin>>n;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
cin>>a[i][j];
add(i,j,a[i][j]);
}
}
cout<<dijkstra();
return 0;
}