Dijkstra的堆优化

先附上一个例题:P3371 【模板】单源最短路径

一眼扫去,最短路。。。

spfa可行,但是今天的主题是Dijkstra:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 10010
#define MAXM 500010
#define MAX 999999999
using namespace std;
int n,m,s,c=1;
int head[MAXN],path[MAXN];
bool vis[MAXN];
struct node{
    int next,to,w;
}a[MAXM<<1];
inline int read(){
    int date=0,w=1;char c=0;
    while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    return date*w;
}
inline void add(int u,int v,int w){
    a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
}
void dijkstra(){
    for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;}
    path[s]=0;
    for(int i=1,k,v;i<=n;i++){
        k=-1;
        for(int j=1;j<=n;j++)if(!vis[j]&&(k==-1||path[k]>path[j]))k=j;
        if(k==-1)break;
        vis[k]=true;
        for(int j=head[k];j;j=a[j].next){
            v=a[j].to;
            if(!vis[v]&&path[v]>path[k]+a[j].w)path[v]=path[k]+a[j].w;
        }
    }
    for(int i=1;i<=n;i++)printf("%d ",path[i]==MAX?2147483647:path[i]);
    printf("\n");
}
int main(){
    int u,v,w;
    n=read();m=read();s=read();
    for(int i=1;i<=m;i++){
        u=read();v=read();w=read();
        add(u,v,w);
    }
    dijkstra();
    return 0;
}

然而,遇上某些题,n<=100,000,怎么办?

比如:P4779 【模板】单源最短路径(标准版)

这时候,堆优化就出场了。


 

堆优化:

堆优化,即用堆来实现O( log2n )时间内找到到起点最短的未被松弛的点。

当然,你需要自定义结构体。

附代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#define MAXN 10010
#define MAXM 500010
#define MAX 999999999
using namespace std;
int n,m,s,c=1;
int head[MAXN],path[MAXN];
bool vis[MAXN];
struct node{
    int next,to,w;
}a[MAXM];
struct Point{
    int x,dis;
    bool operator <(const Point &p)const{
        return dis>p.dis;
    }
};
inline int read(){
    int date=0,w=1;char c=0;
    while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    return date*w;
}
inline void add(int u,int v,int w){
    a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
}
void dijkstra(){
    Point u,v;
    priority_queue<Point> q;
    for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;}
    u.x=s;u.dis=path[s]=0;
    q.push(u);
    while(!q.empty()){
        u=q.top();
        q.pop();
        if(!vis[u.x]){
            vis[u.x]=true;
            for(int i=head[u.x];i;i=a[i].next){
                v.x=a[i].to;
                if(!vis[v.x]){
                    path[v.x]=min(path[v.x],path[u.x]+a[i].w);
                    v.dis=u.dis+a[i].w;
                    q.push(v);
                }
            }
        }
    }
    for(int i=1;i<=n;i++)printf("%d ",path[i]==MAX?2147483647:path[i]);
    printf("\n");
}
int main(){
    int u,v,w;
    n=read();m=read();s=read();
    for(int i=1;i<=m;i++){
        u=read();v=read();w=read();
        add(u,v,w);
    }
    dijkstra();
    return 0;
}

不得不说,这玩意效率虽然没有spfa+SLF高,但是遇上了这题,你也是无可奈何地用它:

P4768 [NOI2018]归程


 

后记:

附上洛谷上的两次提交:(P3371)

朴素Dijkstra:Accepted  100

 1036ms /  7.77MB 
代码:1.11KB C++

Dijkstra+堆优化:Accepted  100

348ms /  9.49MB 
代码:1.3KB C++

 

明显快了不少。

不过出题人没事干也不会卡你的spfa,至少在NOIP这种考试中。。。

posted @   符拉迪沃斯托克  阅读(513)  评论(0编辑  收藏  举报
编辑推荐:
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
阅读排行:
· C# 13 中的新增功能实操
· Ollama本地部署大模型总结
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(4)
· langchain0.3教程:从0到1打造一个智能聊天机器人
· 用一种新的分类方法梳理设计模式的脉络
Live2D
欢迎阅读『Dijkstra的堆优化』
点击右上角即可分享
微信分享提示