最短路算法——Dijkstra
Dijkstra 算法是用来求不存在负环的图的单源最短路算法
算法原理来自最短路的子最短路也必是最短路性质
举一个例子假如A到D的最短路径为A-B-C-D 那么A到C的最短路径必定是A到D的最短路径的子路径A-B-C
可以采用反证法来证明 假设存在A-E-C<A-B-C,则必有A-E-C-D<A-B-C-D,与原设定冲突。所以我们可以利用贪心选择局部最优解来获得最短路,这个思想也是Dijkstra 的算法核心。
算法步骤
主要思想是,将结点分成两个集合:已确定最短路长度的,未确定的。
一开始第一个集合里只有 S 。
然后重复这些操作:
1.对那些刚刚被加入第一个集合的结点的所有出边执行松弛操作。(松弛操作是图论的一个重要性质 具体可去了解Bellman-Ford算法)
2.从第二个集合中,选取一个最短路长度最小的结点,移到第一个集合中。
例题洛谷P3371
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
struct Edge{
int to;
int w;
int next;
}edge[500005];
int tot;
//链式前向星存图
long long dis[500005];
int vis[10005],head[10005];
int u,v,w,n,m,s,cur;
inline void add(int u,int v,int w){
tot++;
edge[tot].to=v;
edge[tot].w=w;
edge[tot].next=head[u];
head[u]=tot;
}
long long temp=(1<<31)-1;
long long Min;
int main(){
fill(dis,dis+500005,temp);
cin>>n>>m>>s;
dis[s]=0;
cur=s;
for(int i=0;i<m;i++){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
while(!vis[cur]){
vis[cur]=1;
for(int i=head[cur];i!=0;i=edge[i].next){//算法步骤1 对cur每个可到的边进行松弛操作
if(!vis[edge[i].to]&&dis[edge[i].to]>dis[cur]+edge[i].w){
dis[edge[i].to]=dis[cur]+edge[i].w;
}
}
Min=temp;//算法步骤2 选取最短路长度最小的结点加入集合1
for(int i=1;i<=n;i++){
if(!vis[i]&&Min>dis[i]){
Min=dis[i];
cur=i;
}
}
}
for(int i=1;i<=n;i++){
printf("%lld ",dis[i]);
}
return 0;
}
// freopen("testdata.in", "r", stdin);
补充操作 利用ptah数组存储路径并 输出
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
struct Edge{
int to;
int w;
int next;
}edge[500005];
int tot;
//Á´Ê½Ç°ÏòÐÇ´æÍ¼
long long dis[500005];
int vis[10005],head[10005];
int path[10005];
int u,v,w,n,m,s,cur,p;
void print(){//由于储存的路径是反过来的 利用栈进行反向输出
stack<int> q;
for(int i=1;i<=n;i++){
p=i;
while(path[p]!=0){
q.push(p);
p=path[p];
}
cout<<p;
while(!q.empty()){
cout<<"->"<<q.top();
q.pop();
}
cout<<endl;
}
}
inline void add(int u,int v,int w){
tot++;
edge[tot].to=v;
edge[tot].w=w;
edge[tot].next=head[u];
head[u]=tot;
}
long long temp=(1<<31)-1;
long long Min;
int main(){
fill(dis,dis+500005,temp);
cin>>n>>m>>s;
dis[s]=0;
cur=s;
for(int i=0;i<m;i++){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
while(!vis[cur]){
vis[cur]=1;
for(int i=head[cur];i!=0;i=edge[i].next){
if(!vis[edge[i].to]&&dis[edge[i].to]>dis[cur]+edge[i].w){
dis[edge[i].to]=dis[cur]+edge[i].w;
path[edge[i].to]=cur;//每次更新时进行保存
}
}
Min=temp;
for(int i=1;i<=n;i++){
if(!vis[i]&&Min>dis[i]){
Min=dis[i];
cur=i;
}
}
}
print();
return 0;
}
// freopen("testdata.in", "r", stdin);
后续操作:利用堆优化让时间复杂度达到O(mlogn)待学习

浙公网安备 33010602011771号