目录
Dijkstra介绍
算法思想
具体步骤
代码实现
Dijkstra链式向前星
优化思路
实现步骤
代码实现
Dijkstra链式向前星堆优化
优化思路
优化步骤
代码实现
参考资料(帮助理解代码)
迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。这是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。
dijkstra采用迭代的办法,贪心算法的原则,每一次都将改变更新源点到不同点的最小边权,遍历没有确定最优解的点。
由于需要逐个找到最小权值O(n),并且在在此基础上更新其他点的最小权值O(n/2),因而算法空间复杂度为O(n)
#include
#include
#include
#include
#define MAXN 1000010
using namespace std;
const int INF=1e9+7;
int n;//point
int m;//edge
bool start;//source point
int map[10000][10000];//memory map
int dis[MAXN];//best way
int visit[MAXN];//whether visited
void init(){
memset(visit,false,sizeof(visit));
for(int i=1;i<=n;i++){
map[i][i]=0;
}
visit[start]=true;
for(int i=1;i<=n;i++){
dis[i]=map[start][i];
}
}
void dijkstra(){
for(int i=1;i<=n;i++)
{
int pos;
int min=INF;
for(int i=1;i<=n;i++){
if(!visit[i]&&min>dis[i]){
min=dis[i];
pos=i;
}
}
visit[pos]=true;
for(int i=1;i<=n;i++){
if(!visit[i]&&map[pos][i](dis[pos]+map[pos][i])){
dis[i]=dis[pos]+map[pos][i];
}
}
}
}
int main()
{
memset(map,INF,sizeof(map));
scanf("%d%d",&n,&m);
scanf("%d",&start);
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
map[u][v]=w;
}
init();
dijkstra();
for(int i=1;i<=n;i++){
cout<
- 在基础dijkstra的代码中,我们采用了以点为核心的转移和存储
- 显然这种方法
很low容易出现时间复杂度和空间复杂度的不便裂开qwq- 因此我们找到一种
更为方便的方式——以边为核心进行转移和存储
#include
#include
#include
#include
#include
#include
#define MAXN 1000010
using namespace std;
const int INF=1e9+77;
int n;//point
int m;//edge
int start;//source point
int dis[MAXN];//best way
bool visit[MAXN];//whether visited
typedef struct Edge{
int next;//next edge with the same head[]
int to;//next point
int w;//len
}Edge;
Edge edge[MAXN];
int head[MAXN];
int tot;
void init()
{
memset(dis,INF,sizeof(dis));
memset(visit,false,sizeof(visit));
memset(head,-1,sizeof(head));
tot=0;
}
void add(int u,int v,int wi)
{
edge[tot].to =v;
edge[tot].w =wi;
edge[tot].next =head[u];
head[u]=tot++;
}
void dijkstra(int s){
int min,pos;
while(1){
min=INF;
pos=-1;
for(int i=1;i<=n;i++)
{
if(!visit[i]&&min>dis[i])
{
min=dis[i];
pos=i;
}
}
if(pos==-1)
{
break;
}
visit[pos]=true;
for(int i=head[pos];i!=-1;i=edge[i].next )
{
int t=edge[i].to ;
if(!visit[t]&&dis[t]>(dis[pos]+edge[i].w ))
{
dis[t]=dis[pos]+edge[i].w ;
}
}
}
return;
}
int main()
{
init();
scanf("%d%d%d",&n,&m,&start);
dis[start]=0;
for(int i=1;i<=m;i++)
{
int u,v,wi;
scanf("%d%d%d",&u,&v,&wi);
add(u,v,wi);
add(v,u,wi);
}
dijkstra(start);
for(int i=1;i<=n;i++)
{
cout<
- 在朴素版dijkstra向链式向前星进行优化的过程中,我们巧妙的使用以点计数变为以边计数的优化方式缓解了空间的压力
- 而在链式向前星向堆优化的过程中,我们则借助“堆”这一巧妙地结构来完成
- 这里用到小根堆这个概念
- 因为采用贪心策略进行迭代,而贪心的原则就是选择最近的点,故可以使用小根堆
参考文章
本文链接:c++优先队列(priority_queue)用法详解_吕白_的博客-CSDN博客_c++ priority_queue
本文链接:数据结构之堆_Hidden.Blueee的博客-CSDN博客_堆
(洛谷P4779)
#include
#include
#include
#include
#include
#include
#define MAXN 1000010
using namespace std;
inline int read(){
int f = 1, x = 0;char ch = getchar();
while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
return x * f;
}
typedef struct Edge{
int w;
int next;
int to;
}E;
E edge[MAXN];
const int INF=1e9+77;
int n;//点
int m;//edge
int s;//source point
int dis[MAXN];
bool visit[MAXN];
int head[MAXN];
int cnt=0;
struct node{
int dis;
int pos;
bool operator < (const node &x)const{
return x.dis q;
void dijkstra(){
dis[s]=0;
q.push((node){0,s});
while(!q.empty()) {
node tmp=q.top() ;
q.pop() ;
int value=tmp.dis ,posn=tmp.pos ;
if(visit[posn]){
continue;
}
visit[posn]=true;
for(int i=head[posn];i!=-1;i=edge[i].next){
int t=edge[i].to ;
if(dis[t]>dis[posn]+edge[i].w ){
dis[t]=dis[posn]+edge[i].w ;
if(!visit[t]){
q.push((node){dis[t],t});
}
}
}
}
}
int main()
{
init();
n=read(),m=read(),s=read();
for(int i=1;i<=m;i++){
int u,v,w;
u=read();
v=read();
w=read();
add(u,v,w);
}
dijkstra();
for(int i=1;i<=n;i++){
printf("%d ",dis[i]);
}
return 0;
}
本文链接:C语言中的typedef struct用法_华华华-CSDN博客
原文链接:[C++基础]队列
本文链接:强制转换_陌陌Jun的博客-CSDN博客
本文链接:std::的概念与作用_玮哥的博客-CSDN博客