最短路算法——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)待学习

posted @ 2020-09-23 21:55  一个经常掉线的人  阅读(207)  评论(0)    收藏  举报