Dijkstra算法
Dijkstra算法
1.最短路问题
在图论中,最短路问题分为单源最短路和多源最短路。
其中,单源最短路又分为存在负权边和不存在负权边两种。
Dijkstra算法就是来解决不存在负权边的最短路问题的。
2.Dijkstra算法思想
如果图是不带负权的有向图或者无向图,从起点 \(v0\) 每次新扩展一个距离最短的点,再以这个点为中间点,更新起点到其他所有点的距离。
由于所有边权都为正,故不会存在一个距离更短的没被扩展过的点,所以这个点的距离永远不会再被改变,因而保证了算法的正确性。
3.Dijkstra算法步骤
①初始化 \(d[v0]=0\),源点到其他点的距离值 \(d[i]=∞\)。
②经过 \(n\) 次如下步骤操作,最后得到 \(v0\) 到 \(n\) 个顶点的最短距离:
A.选择一个未标记的点 \(k\) 并且 \(d[k]\) 的值是最小的;
B.标记点 \(k\),即 \(f[k]=1\);
C.以 \(k\) 为中间点,修改源点 \(v0\) 到其他未标记点 \(j\) 的距离值\(d[j]\) 。
解释:
\(f[i]\):值为\(true\),已求得最短距离,在集合1中;
值为\(false\),在集合2中。
开始点(源点):\(v0\)。
\(d[i]\):顶点 \(v0\) 到 \(i\) 的最短距离。
初始:
\(d[v0]=0\);\(d[i]=a[v0][i]\)。
这些的代码实现
memset(d,0x3f,sizeof(d));//初始化为正无穷
d[1]=0;
for(int i=1;i<=n;i++){//核心代码
int k=-1;
for(int j=1;j<=n;j++)
if(!f[j]&&(k==-1||d[k]>d[j]))//如果点j没有确定最短路且k还没有被赋值或它不是最短的
k=j;
f[k]=true;//确定k点最短路
for(int j=1;j<=n;j++)
d[j]=min(d[j],d[k]+g[k][j]);//比较原始j的最短路和新路大小并赋值
}
算法的时间复杂度为 \(O(n^2)\),因为每次寻找未标记的结点需要耗时 \(O(n)\),可以用堆优化此处,时间复杂度降为 \(O(mlogn)\)。
4.代码实现
#include<iostream>
#include<cstring>
using namespace std;
const int N=505;
int n,m;//n个点,m条边
int g[N][N];//邻接矩阵存储
int d[N];//1号点到任意点的距离
bool f[N];//有没有确定最短路
int dij(){//Dijkstra算法
memset(d,0x3f,sizeof(d));//初始化为正无穷
d[1]=0;
for(int i=1;i<=n;i++){//核心代码
int k=-1;
for(int j=1;j<=n;j++)
if(!f[j]&&(k==-1||d[k]>d[j]))//如果点j没有确定最短路且k还没有被赋值或它不是最短的
k=j;
f[k]=true;//确定k点最短路
for(int j=1;j<=n;j++)
d[j]=min(d[j],d[k]+g[k][j]);//比较原始j的最短路和新路大小并赋值
}
if(d[n]==0x3f3f3f3f) return -1;
else return d[n];
}
int main(){
cin>>n>>m;
memset(g,0x3f,sizeof(g));//初始化为正无穷
for(int i=1;i<=m;i++){
int x,y,z;// x到 y的有向边,长度为z
cin>>x>>y>>z;
g[x][y]=min(g[x][y],z);//在x到y的边中取最小的值
}
cout<<dij();
return 0;
}
注释已全部标出,不理解可以多看几遍。
完awa~
不多不少90行。
如果觉得还不错就点个赞吧,您的支持就是本蒟蒻最大的动力。