最短路——Dijkstra算法
(〇)框架
本文章着重讲价其中的Dijkstra算法
(一)Dijkstra算法
使用前提:没有负权的边
Dijkstra求最短路径思路
基于贪心思想
,给定图G,边集合E,顶点集合V。每次求出从起点Vs到一个顶点Vi的最短路径,然后以Vi为中转点,用Vs到Vi的最短路径 和 其他尚未求出最短路径的点的路径长度 进行必要的修改,使之成为当前最优的最短路径。
进行n-1
此后结束,因此我们也可以用它来判断是否存在负权环。
总结一下: 每次选择【未确定】最短路径中,到原点【路径长度最小的点】
实现?
基于上述所说的几点,我们来思考一下如何实现:
1.用vis[]数组储存未确定最短路径的点
2.用dis[]数组储存当前点距离原点的最短距离
Dijkstra求最短路流程:
1.定义dis[](初值赋无穷大),vis[]数组,集合S(储存已找到的从Vs出发的最短路径的集合)
2.选择(离当前点)距离最短的顶点Vp,加入集合S,vis[Vp]=1;
3.更新vis[]数组中各个顶点到起点s的距离。之所以更新vis[]数组中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;
4.重复2、3步骤知道遍历完所有顶点
图解
例题:[模板]单源最短路
题目描述
给定一个 n 个点,m 条有向边的带非负权图,请你计算从 s 出发,到每个点的距离。
数据保证你能从 s 出发到任意点。
输入格式
第一行为三个正整数 n,m,s。第二行起 m 行,每行三个非负整数 ui,vi,wi,表示从 ui 到 vi 有一条权值为 wi 的有向边。
输出格式
输出一行 n 个空格分隔的非负整数,表示 s 到每个点的距离。
输入
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
输出
0 2 4 3
代码及解释
#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int maxn=500005;
int n,m,s,u,v,w;
struct node{
int to,len;
};
vector<node> f[maxn];
long long dis[maxn];
int vis[maxn];
void dijkstra(int t)
{
priority_queue<pii,vector<pii>,greater<pii> > q;
dis[t]=0;//起点距离为零
q.push(pii(0,t));//起点输入
while(!q.empty()){//只要队列不为空,就一直循环下去
pii x=q.top();//将队列顶部的元素顶点存下来
q.pop();//弹出队顶元素
int tt=x.second;
if(vis[tt]) continue;//判断是否访问过
vis[tt]=1;//标记为访问过
for(int i=0;i<f[tt].size();i++){
node a=f[tt][i];
if(dis[a.to]>dis[tt]+a.len){
dis[a.to]=dis[tt]+a.len;
q.push(pii(dis[a.to],a.to));
}
}
}
}
int main()
{
cin>>n>>m>>s;
for(int i=0;i<m;i++){
cin>>u>>v>>w;
f[u].push_back({v,w});
}
for(int i=1;i<=n;i++){
dis[i]=114514191;
}//1145141919810
memset(vis,0,sizeof(vis));
dijkstra(s);
for(int i=1;i<=n;i++){
if(dis[i]!=114514191)
cout<<dis[i]<<endl;
}
return 0;
}
完结撒花
(后续将更新其他最短路算法,敬请期待)
(图片来源)wmy0217_ https://blog.youkuaiyun.com/wmy0217_heroacool
https://heroacool.blog.youkuaiyun.com/
我只是想要一个小小的赞👍