• Dijkstra


    Dijkstra

    核心思想

    遍历每一个点,找到离点最近的点

    类似于bfs,把该点可以拓展的点都遍历一遍,找到距离最近的且没有被取过(被遍历过)的点,然后用这个点来更新其他的点

    核心代码

    //除1号结点外,其他均初始为无穷大
    memset(dist,0x3f,sizeof dist);
        dist[1]=0;
    //这里进行n次迭代,是为了把n个点都按照距离从小到大的顺序放入st
        for(int i=0;i<n;i++){
            // 便于更新第一个点
            int t=-1;
            for(int j=1;j<=n;j++)
              if(!st[j]&&(t==-1||dist[j]<dist[t])) t=j;
            //将t加到已经取过的点中
            st[t]=true;  
            //用t更新其他点的距离
            for(int j=1;j<=n;j++)  
              dist[j]=min(dist[j],dist[t]+g[t][j]);
        }
         //路径不存在
        if(dist[n]==0x3f3f3f3f) return -1;
        else return dist[n];
    

    以下代码的具体流程:

    for(int j=1;j<=n;j++)  //用t更新其他点的距离
              dist[j]=min(dist[j],dist[t]+g[t][j]);
    

    首先我们找点第一个点,假设这个点是第一个点,那么这个循环就不会被执行,因为这个t类似于中间点,

    1 --> 2 dist = 10

    1 --> t dist = 5

    t --> 2 dist = 2

    dist[2] = min(dist[2],dist[t] + g [t] [2]),其中g (t,2)代表 点 t 到点 2的距离

    dist (t) 表示 起点 到 t 的距离

    邻接矩阵实现 [题目链接][849. Dijkstra求最短路 I - AcWing题库

    #include <iostream>
    #include <math.h>
    #include <string.h>
    
    using namespace std;
    
    const int N = 1e6+10;
    
    int g[1010][1010];
    int n,m;
    
    bool st[N];
    int dist[N];
    
    void dijkstra(){
        memset(dist,0x3f,sizeof(dist));
        dist[1] = 0;
        for (int i = 1;i <= n;i++){
            int t = -1;
            for (int j = 1;j <= n;j++){
                if (!st[j] && (t == -1 || dist[t] > dist[j])){
                    t = j;
                }
            }
            st[t] = true;
            for (int j = 1;j <= n;j++){
                dist[j] = min(dist[j],dist[t]+g[t][j]);
            }
        }
    }
    
    int main(){
        memset(g,0x3f,sizeof(g));
        cin >> n >> m;
        for (int i = 1;i <= m;i++){
            int a,b,c;
            cin >> a >> b >>c;
            g[a][b] = min(g[a][b],c);
        }
        dijkstra();
        if (dist[n] == 0x3f3f3f3f)cout << -1 << endl;
        else
            cout << dist[n] <<endl;
    }
    

    链式前向星实现

    链式前向星:

    ll e[N],ne[N],h[N],w[N],idx;
    //e[] 存放下一个节点
    // ne[] 为下一个边的起点
    // w[] 存放两条边之间的权重
    // h[] 存放该节点
    // idx 记录总的边数 相当于给每个边一个编号 
    
    void add(ll a,ll b,ll c){
        //记录节点与a链接的节点b,点与点之间的权重为c 
        e[idx] = b;
        w[idx] = c;
        //下一个节点为h[],也就是
        ne[idx] = h[a];
        //更新h[a] 表示添加边的位置
        h[a] = idx++;
    }                        
    

    朴素版

    #include <iostream>
    #include <algorithm>
    #include <string.h>
    
    using namespace std;
    
    const int N = 1e6+10;
    
    int n,m;
    int dist[N];
    bool st[N];
    int e[N],ne[N],h[N],idx,w[N];
    
    
    void add(int a,int b,int c){
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    
    void dijkstra(){
        memset(dist,0x3f,sizeof(dist));
        dist[1] = 0;
        for (int i = 1;i <= n; i++){
                int t = -1;
            for (int j = 1;j <= n;j++){
                
                if (!st[j] && (t == -1 || dist[t] > dist[j])){
                    t = j;
                }
            }
            st[t] = true;
            //k是j的直达点,
            //t是j到k的中间点
            //二者取较小值
            for (int j = h[t];j != -1;j = ne[j]){
                int k = e[j];
                dist[k] = min(dist[k],dist[t]+w[j]);
            }
        }
    }
    
    int main(){
        memset(h,-1,sizeof(h));
        cin >> n >> m;
        for (int i = 1;i <= m; i++){
            int a,b,c;
            cin >> a >> b >> c;
            add(a,b,c);
        }
    
        dijkstra();
        if (dist[n] == 0x3f3f3f3f)cout << -1 << endl;
        else cout << dist[n] << endl;
        return 0;
    }
    
    

    堆优化 [题目链接](850. Dijkstra求最短路 II - AcWing题库)

    #include <iostream>
    #include <algorithm>
    #include <string.h>
    #include <queue>
    
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>PII;
    const int N = 1e6+10;
    
    int n,m,dist[N];
    bool st[N];
    int h[N],ne[N],e[N],w[N],idx;
    
    void add(int a,int b,int c){
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    
    void dijkstra(){
        memset(dist,0x3f,sizeof(dist));
        //通过有限队列对dij进行优化,每次取距离最近的点
        priority_queue<PII,vector<PII>,greater<PII>>q;
        dist[1] = 0;
        //第一个参数是距离,第二是节点
        q.push({0,1});
        while (q.size()){
            PII t = q.top();
            q.pop();
            int v = t.second,d = t.first;
            if (st[v])continue;
            st[v] = true;
            for (int i = h[v];i != -1;i = ne[i]){
                int j = e[i];
     	    //如果距离大于,中间点加上一条边的距离那就把,距离更新并与点加入队列
                if(dist[j] > d + w[i]){
                    dist[j] = d + w[i];
                    q.push({dist[j],j});
                }
            }
        }
    }
    
    int main(){
        memset(h,-1,sizeof(h));
        cin >> n >> m;
        for (int i = 1;i <= m;i++){
            int a,b,c;
            cin >> a >> b >> c;
            add(a,b,c);
        }
        dijkstra();
        if(dist[n]==0x3f3f3f3f)cout <<-1 << endl;
        else cout <<  dist[n] << endl;
        return 0;
    }
    

    [[849. Dijkstra求最短路 I - AcWing题库]:

  • 相关阅读:
    四,redis6版本的使用部署
    记录篇-浪潮服务器raid卡
    sudo漏洞解决方案--源码转rpm包(spec文件编写)
    关闭 Chrome 浏览器阅读清单功能
    【转译】如何成为一个数据工程师?
    Python 用最小堆获取大量元素 topk 大个元素
    Python 实现二分查找
    Python 排序算法之堆排序,使用 heapq 实现
    Python 排序算法之归并排序
    Python 排序算法之快速排序
  • 原文地址:https://www.cnblogs.com/AChappy/p/16115754.html
Copyright © 2020-2023  润新知