Dijkstra算法C++

系列文章目录

Dijkstra算法
Ballman_ford算法
Spfa算法
Floyd算法


文章目录

  • 系列文章目录
  • 一、朴素版本
  • 二、堆优化版本
  • 总结


一、朴素版本

时间复杂度:$O(n^2)$
数据量比较密集时:数据存储用邻接矩阵g[][]

较大值MAX选用0x3f3f3f3f:32bit中通常int最大值为0x7fffffff,但是此处需要对MAX进行加法,0x7fffffff + 3为负数,显然不符合最短路径算法中的松弛操作,因此,如果能满足无穷大加无穷大结果依然是无穷大就完美符合松弛操作。0x3f3f3f3f的十进制是1061109567,是 1 0 9 10^9 109级别的,而一般场合下的数据都是小于10^9的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。

0x3f3f3f3f是一个很有用的数值,它是满足以下两个条件的最大整数。
1、整数的两倍不超过0x7f7f7f7f,即int能表示的最大正整数。
2、整数的每8位(每个字节)都是相同的。
我们在程序设计中经常需要使用 memset(a, val, sizeof a)初始化一个数组a,该语句把数值 val(0x00~0xFF)填充到数组a 的每个字节上,所以用memset只能赋值出“每8位都相同”的 int。
当需要把一个数组中的数值初始化成正无穷时,为了避免加法算术上溢出或者繁琐的判断,我们经常用 memset(a, 0x3f, sizeof(a)) 给数组赋0x3f3f3f3f的值来代替。

朴素Dijkstra算法

  1. 初始化距离数组,起点距离设置为0;
  2. 遍历n次,每次确认一个最短路径店;
  3. 找到当前到起点距离最短且未确认的点,并修改状态;
  4. 更新其它点到距离最小点的距离
#include
using namespace std;
#include
int n,m;

//稠密图用邻接矩阵
const int N= 510, MAX = 0x3f3f3f3f;
int g[N][N];
int d[N];//节点间距离矩阵,当前点到1的距离数组
bool st[N];//状态确认数组,true表示当前状态已经确认为最短值,不可再修改


void Dijkstra(){
    //初始化
    memset(d, MAX, sizeof d);
    d[1]=0;//st[1]=true;
    //遍历n次,每次确认一个节点
    for(int i=0;i<n;i++){
        //找到距离最短的路径点
        int min_idx, min_dis = MAX;
        for(int j=1;j<=n;j++){
            //当前点状态为确定 && 当前点到1的距离小于min_dis
            if(!st[j] && d[j]<min_dis){
                min_idx = j;
                min_dis = d[j];
            }
        }
        st[min_idx]=true;
        //更新距离
        for(int j=1;j<=n;j++){
            d[j] = min(g[min_idx][j]+d[min_idx], d[j]);
        }
    }
}

int main(){
    cin>>n>>m;
    memset(g, MAX, sizeof g);
    int a, b, v;
    while(m--){
        cin>>a>>b>>v;
        g[a][b]=min(v,g[a][b]);
    }
    Dijkstra();
    if(d[n]==MAX) cout<<-1;
    else cout<<d[n];
    
    return 0;
}

二、堆优化版本

时间复杂度:$O(mlogm)$

堆优化版的dijkstra是对朴素版dijkstra进行了优化,在朴素版dijkstra中时间复杂度最高的寻找距离
最短的点O(n^2)可以使用最小堆优化。

  1. 一号点的距离初始化为零,其他点初始化成无穷大。
  2. 将一号点放入堆中。
  3. 不断循环,直到堆空。每一次循环中执行的操作为:
    弹出堆顶(与朴素版diijkstra找到S外距离最短的点相同,并标记该点的最短路径已经确定)。
    用该点更新临界点的距离,若更新成功就加入到堆中。
#include
using namespace std;
#include
#include

//稀疏图的Dijkstra算法
//稠密图用邻接矩阵,稀疏图用邻接表

int n, m;
const int N=150010 , MAX=0x3f3f3f3f;
int idx, e[N], h[N], ne[N], v[N];

int d[N];//存储当前点到1的最短距离
bool st[N];//存储当前点是否确认
typedef pair<int,int> PII;


void add(int a, int b, int c){
    e[idx]=b;
    v[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}

void Dijkstra(){
    memset(d, MAX, sizeof d);
    //初始化起点
    d[1]=0;
    priority_queue<PII , vector<PII>, greater<PII>> heap;//小顶堆
    heap.push({0,1});//起点放入
    
    //
    while(heap.size()){
        //查找距离最近的且未确认的点
        PII minn = heap.top();
        heap.pop();
        int min_idx = minn.second, min_dis = minn.first;
        if(st[min_idx]) continue;//特:如果当前点已经确认则continue
        //更新新起点
        st[min_idx] = true;
        //更新新起点连通点的最短距离
        for(int i = h[min_idx]; i!=-1; i=ne[i]){
            int j=e[i];
            if(d[j]>min_dis+v[i]){
                d[j]=min_dis+v[i];
                heap.push({d[j],j});
            }
        }
    }
}


int main(){
    cin>>n>>m;
    memset(h,-1,sizeof h);
    int a,b,c;
    while(m--){
        cin>>a>>b>>c;
        add(a,b,c);
    }
    Dijkstra();
    if(d[n] == MAX) cout<< -1;
    else cout<<d[n];
    return 0;
}

总结

你可能感兴趣的:(算法刷刷刷,算法,c++,图论,数据结构,贪心算法)