【最短路】Dijkstra+ 链式前向星+ 堆优化(优先队列)

Dijkstra+ 链式前向星+ 优先队列

 

Dijkstra算法

  Dijkstra最短路算法,个人理解其本质就是一种广度优先搜索。先将所有点的最短距离Dis[ ]都刷新成∞(涂成黑色),然后从起点x (Dis[x]= 0, Dis[]值最小 )开始查询;先将x 加入(涂成灰色),对x 的所有边进行遍历,对所有搜索到的点x+ 1 进行松弛(刷新),若经过x 点的松弛,得到的距离小于原来的值:Dis[x]+ dis(x, x+ 1) < Dis[x+ 1], 则用新值刷新,把x+ 1加入(涂成灰色);当x 的所有边都完毕,邻接的点都松弛完毕后,把x 退出(涂成白色),继续从下一个Dis[ ]最小的点开始;重复上述步骤,直到所有的点都涂成白色,退出。

链式前向星

  这个不说了,之前的帖子里说过,拉到最下面就是。

堆优化

  利用优先队列,对数据结构感兴趣的可以去看一下堆,这里就不说了,会用优先队列就行。

最短路计算:Dijkstra链式前向星优先队列

  下面进入正题。

  还是拆分代码和用例题来解释。

①链式前向星建图

using namespace std;
const int MAX_E= 2000010;
const int MAX_V= 200010;
const int inf= 0x3f3f3f3f;

struct ENode
{
    int to;       //终点;
    int w;        //权;
    int type;     //路的类型;
    int next;     //下一条路的地址;
};
ENode Edegs[MAX_E];
int Head[MAX_V]; //点Vi的第一条边的地址;
int Dis[MAX_V];  //点Vi到起点的最短距离;
int main()
{
    int n, m, s;
    cin >> n >> m >> s;
    int t, a, b, w;
    memset(Head, -1, sizeof(Head));
    for (int i= 0; i< m; i ++)
    {
        cin >>a >>b >>w;
        Edegs[i].to= b;
        Edegs[i].w= w;
        Edegs[i].next= Head[a];
        Head[a]= i;
////        有向图建图多加一次边,m 变成m* 2;
//        ++ i;
//        Edegs[i].to= a;
//        Edegs[i].w= w;
//        Edegs[i].next= Head[b];
//        Head[b]= i;
    }
    return 0;
}

②Dijkstra+ 优先队列

int Head[MAX_V]; //点Vi的第一条边的地址;
int Dis[MAX_V];  //点Vi到起点的最短距离;
struct cmpx
{
    //优先队列的排序函数;
    bool operator()(int &a,int &b)const
    {
        return Dis[a]> Dis[b];
    }
};
void Dijkstra(int x)
{
    //用优先队列寻找Dis[]最小点;
    //代替遍历搜索,节约时间;
    priority_queue<int,vector<int>,cmpx > q;
    memset(Dis, inf, sizeof(Dis));   //染成黑色;
    Dis[x]= 0;
    q.push(x);                       //将x 加入队列,涂成灰色;

    while (! q.empty())
    {
        int u= q.top();
        q.pop();                     //将x 出队列,涂成白色;
        for (int k= Head[u]; k!= -1; k= Edegs[k].next )
        {
            int v= Edegs[k].to;
            if (Dis[v]> Dis[u]+ Edegs[k].w )
            {
                Dis[v]= Dis[u]+ Edegs[k].w;
                q.push(v);           //将x+ 1加入队列,涂成灰色;
            }
        }
    }
}

下面是洛谷上一道最短路入门题,验证一下正确性:P3371 【模板】单源最短路径(弱化版)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int MAX_E= 2000010;
const int MAX_V= 200010;
const int inf= 0x3f3f3f3f;

struct ENode
{
    int to;       //终点;
    int w;        //权;
    int type;     //路的类型;
    int next;     //下一条路的地址;
};
ENode Edegs[MAX_E];
int Head[MAX_V]; //点Vi的第一条边的地址;
int Dis[MAX_V];  //点Vi到起点的最短距离;
struct cmpx
{
    //优先队列的排序函数;
    bool operator()(int &a,int &b)const
    {
        return Dis[a]> Dis[b];
    }
};
inline int read()
{
    //快速读入;
    int X= 0,w= 1;
    char ch= 0;
    while(ch<‘0‘ || ch>‘9‘)
    {
        if(ch==‘-‘) w= -1;
        ch= getchar();
    }
    while(ch>= ‘0‘ && ch<= ‘9‘) X= (X<< 3)+(X<< 1)+(ch-‘0‘),ch=getchar();
    return X* w;
}
void Dijkstra(int x)
{
    //用优先队列寻找Dis[]最小点;
    //代替遍历搜索,节约时间;
    priority_queue<int,vector<int>,cmpx > q;
    memset(Dis, inf, sizeof(Dis));   //染成黑色;
    Dis[x]= 0;
    q.push(x);                       //将x 加入队列,涂成灰色;

    while (! q.empty())
    {
        int u= q.top();
        q.pop();                     //将x 出队列,涂成白色;
        for (int k= Head[u]; k!= -1; k= Edegs[k].next )
        {
            int v= Edegs[k].to;
            if (Dis[v]> Dis[u]+ Edegs[k].w )
            {
                Dis[v]= Dis[u]+ Edegs[k].w;
                q.push(v);           //将x+ 1加入队列,涂成灰色;
            }
        }
    }
}

int main()
{
    int n, m, s;
    cin >> n >> m >> s;
    int t, a, b, w;
    memset(Head, -1, sizeof(Head));
    for (int i= 0; i< m; i ++)
    {
        cin >>a >>b >>w;
        Edegs[i].to= b;
        Edegs[i].w= w;
        Edegs[i].next= Head[a];
        Head[a]= i;
////        有向图建图多加一次边,m 变成m* 2;
//        ++ i;
//        Edegs[i].to= a;
//        Edegs[i].w= w;
//        Edegs[i].next= Head[b];
//        Head[b]= i;
    }
    Dijkstra(s);
    for (int i = 1; i <= n; i ++)
    {
        if (i!= 1) printf(" ");
        if (Dis[i]== inf)
        {
            printf("2147483647");
        }
        else
        {
            printf("%d", Dis[i]);
        }
    }
    printf("\n");
    return 0;
}

完整程序

谢谢观看这篇随笔!

原文地址:https://www.cnblogs.com/Amaris-diana/p/10551464.html

时间: 2024-11-07 00:32:44

【最短路】Dijkstra+ 链式前向星+ 堆优化(优先队列)的相关文章

dijkstra算法:链式前向星+堆优化

最近发现struct板子真的好用. 1 #include<bits/stdc++.h> 2 #define ll long long 3 #define scan(i) scanf("%d",&i) 4 #define scand(i) scanf("%lf",&i) 5 #define scanl(i) scanf("%lld",&i) 6 #define f(i,a,b) for(int i=a;i<

最短路 SPFA()链式前向星

在极端情况下,图特别大,用邻接链表也会超空间限制,此时需要用到链式前向星来存图. 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int inf = INT_MAX / 10; 5 const int num = ???; 6 struct Edge{ 7 int to, next, w;//edge[i]的i就是起点,终点to,权值w,相同起点的下一条边next 8 }edge[num]; 9 int n, m, cnt;

单元最短路径算法模板汇总(Dijkstra, BF,SPFA),附链式前向星模板

一:dijkstra算法时间复杂度,用优先级队列优化的话,O((M+N)logN)求单源最短路径,要求所有边的权值非负.若图中出现权值为负的边,Dijkstra算法就会失效,求出的最短路径就可能是错的. 设road[i][j]表示相邻的i到j的路长U集合存储已经求得的到源点最短路径的节点,S集合表示还没求得的节点dis[i]表示i到源节点(设为0)的最短路径vis[i]=1表示i节点在U集合中 刚开始dis[0]=0,vis[0]=1;dis[i]=maxn,vis[i]=0;for 1 to

UESTC30-最短路-Floyd最短路、spfa+链式前向星建图

最短路 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的T-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗? Input 输入包括多组数据. 每组数据第一行是两个整数NN ,MM (N≤100N≤100 ,M≤10000M≤1000

最短路 spfa 算法 &amp;&amp; 链式前向星存图

推荐博客  https://i.cnblogs.com/EditPosts.aspx?opt=1 http://blog.csdn.net/mcdonnell_douglas/article/details/54379641 spfa  自行百度 说的很详细 spfa 有很多实现的方法  dfs  队列  栈  都可以 时间复杂度也不稳定 不过一般情况下要比bellman快得多 #include <stdio.h> #include <math.h> #include <st

poj-1459-最大流dinic+链式前向星

title: poj-1459-最大流dinic+链式前向星 date: 2018-11-22 20:57:54 tags: acm 刷题 categories: ACM-网络流-最大流 概述 这道是一道网络流里最大流的板子题,,, 暑期集训网络流草草水过,,连基本的算法都不知道有哪些,,,更别提怎么实现了,,,只知道网络流的大致的概念,, 今天花了一天的时间重新学习了一波,,,本以为这东西很简单,,,没想到不仅算法的实现一大堆的东西,,就连题目都有时候看不懂,,,,感受就是网络流的题不仅算法实

链式前向星

重要的事情说三遍 明天不学会链式前向星我绝食三天

图的存储结构:邻接矩阵(邻接表)&amp;链式前向星

[概念]疏松图&稠密图: 疏松图指,点连接的边不多的图,反之(点连接的边多)则为稠密图. Tips:邻接矩阵与邻接表相比,疏松图多用邻接表,稠密图多用邻接矩阵. 邻接矩阵: 开一个二维数组graph[ ][ ]来记录图中点a与点b之间是否连通,初始化为0(或者-1之类的看情况):如果图中有可忽略的重边(如 只需重边中的最小边或最大边),则保存需要的那条边的边权,但如果有无法忽略的重边,就一定不要用邻接矩阵. int graph[MAXN][MAXN]; void graphInit() { me

HDU3342 Legal or Not【拓扑排序】【链式前向星】

Legal or Not Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4633    Accepted Submission(s): 2115 Problem Description ACM-DIY is a large QQ group where many excellent acmers get together. It is