一、算法流程
Dijkstra算法流程如下
- 初始化,集合K中加入结点1,结点1到结点1最短距离为0,到其它结点为无穷(或不确定)。
- 遍历与集合K中结点直接相邻的边(U,V,C),其中U属于集合K,V不属于集合K,计算由结点1出发按照已经得到的最短路到达U,再由U经过该边到达V时的路径长度。比较所有与集合K中结点直接相邻的非集合K结点该路径长度,其中路径长度最小的结点被确定为下一个最短路径确定的结点,其最短路径长度即为这个路径长度,最后将该结点加入集合K。
- 若集合K中已经包含了所有的点,算法结東;否则重复步骤2。
二、实例:
1. 牛客网 最短路径
因为需要考虑s是否可以到达t,因此先用djs算出最短路径,同时存储前驱结点,最后用DFS深度遍历路径看起点终点是否相连
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
#define N 10001
#define INF 100000
struct edge{
int next; //下一跳
int W; //权重
};
int n,m,S,T; //n,m,起点S和终点T
int dis[N]; //最小距离
bool vis[N]; //是否访问过
bool flag=false; //起点能够到达终点
void dfs(int d,vector<int> pre[N]){
if(d==S){
flag=true;
return;
}
else{
//权重相同时有多个前驱节点
for(int i=0;i<pre[d].size();i++){
dfs(pre[d][i],pre);
}
}
}
void dijsktra(vector<int> pre[N],vector<edge> edges[N]){
//初始化
int nextG=S;
dis[S]=0;
vis[S]=true;
for(int i=0;i<n;i++){
for(int j=0;j<edges[nextG].size();j++){
int t=edges[nextG][j].next; //下一跳
int w=edges[nextG][j].W; //长度
if(vis[t]==true) continue;
//更新信息
if(dis[t]==-1||dis[t]>dis[nextG]+w){
dis[t]=dis[nextG]+w;
pre[t].clear();
pre[t].push_back(nextG);
}
//权重相同时有多个前驱节点
else if(dis[t]==-1||dis[t]==dis[nextG]+w){
dis[t]=dis[nextG]+w;
pre[t].push_back(nextG);
}
}
int minDis=INF;
//选取最小的作为下一跳
for(int j=1;j<n;j++){
if(dis[j]!=-1&&dis[j]<minDis&&vis[j]==false){
minDis=dis[j];
nextG=j;
}
}
vis[nextG]=true; //标记已访问
}
}
int main(){
vector<edge> egdes[N]; //邻接边
vector<int> pre[N]; //前驱节点
fill(dis,dis+N,-1);
scanf("%d %d %d %d",&n,&m,&S,&T);
while(m--){
int a,b,w;
scanf("%d%d%d",&a,&b,&w); //节点a,b和权重c
edge tmp;
tmp.next=b;
tmp.W=w;
egdes[a].push_back(tmp); //单向,只加入一边
}
dijsktra(pre,egdes);
dfs(T,pre); //检验起点终点是否相通
if(flag)
printf("%d",dis[T]);
else
printf("%d",-1);
return 0;
}