零基础学算法100天第1天——Dijkstra(图解最短路算法)(下)

简介: 零基础学算法100天第1天——Dijkstra(图解最短路算法)

🍅5.Dijkstra核心代码实现


       为了方便大家理解和记忆,我将代码按照上面的逻辑分成几个板块方便大家记忆。


1.初始化操作        

//所有距离初始化为正无穷
 Arrays.fill(dist,0x3f3f3f3f);
 //起点初始化为0,主要看起点的编号是几,这里默认为1
 dist[1]=0;


2.寻找找到距离起点最近且未标记过的点


int t=-1;
for(int j=1;j<=n;++j)
{
     if(!st[j]&&(t==-1||dist[t]>dist[j])) t=j;
 }
 st[t]=true;


       t表示距离起点最近且未标记过的点,刚开始默认为-1,表示没有,然后依次遍历所有的点,首先必须要保证该点未使用过,所以st[j]必须为flase。其次如果t=-1说明t还没选定,那么说明可以直接选择该点,然后如果当前dist[j]<dist[t]说明我们找到一个更小的点了,于是将t更新为这个更小的点。当然别忘记让st[t]为true。


3.利用步骤2找到的点去更新其他点的最短路径  


for(int j=1;j<=n;++j){
      dist[j]=Math.min(dist[j],dist[t]+g[t][j]);
 }


    判断的方法和我们前面的样例说的是一模一样的,这样更新下每个点就好。


   完整函数核心代码:


static int dijkstra(){
        //填充函数
        Arrays.fill(dist,0x3f3f3f3f);
        dist[1]=0;
        //因为总共有n个点,所以我们要迭代n次
        for(int i=0;i<n;++i){
            int t=-1;
            for(int j=1;j<=n;++j){
                if(!st[j]&&(t==-1||dist[t]>dist[j])) t=j;
            }
            if(t==n) break;
            st[t]=true;
             for(int j=1;j<=n;++j){
               dist[j]=Math.min(dist[j],dist[t]+g[t][j]);
           }
        }
        //当遍历完毕以后如果到点n的距离仍然是无穷大
        //说明无法从起点到达该点,我们返回-1,反正dist[n]就是到n的最短距离
        if(dist[n]==0x3f3f3f3f) return -1;
        else return dist[n];
    }


🍆6.最短路模板题练手


🍦1.网络延迟时间


image.png    


题目链接:网络延迟时间https://leetcode-cn.com/problems/network-delay-time/


      为了方便大家练习,我就从力扣上找了模板题给大家练习。


      首先大家遇到最短路径问题,一定要先分析数据规模,本题的n最大为100,所以我们是可以使用朴素的Dijkstra。我们直接套用上面的模板即可。


      但是这题有几个需要注意的地方:


1.什么时候返回-1?      


       因为要达到所有的点,所以当我们判断到某个点的最短路径是正无穷时,说明无法到达,返回-1


2.最大时间是多少?


      因为要保证所有节点都收到信息,所以所有结点收到信息的时间也就是最后一个结点收到的时间,我们在到达所有节点的世界里取一个max即可。


       代码转换:


class Solution {
    int N=110;
    int[][] g=new int[N][N];
    int[] dist=new int[N];
    boolean[] st=new boolean[N];
    public int networkDelayTime(int[][] times, int n, int k) {
        for(int i=0;i<=n;++i){
            Arrays.fill(g[i],0x3f3f3f3f);
        }
            for(int[] nums:times){
                int a=nums[0];
                int b=nums[1];
                int c=nums[2];
                g[a][b]=c;
            }
        return dijkstra(n,k);
    }
    int dijkstra(int n,int k){
        Arrays.fill(dist,0x3f3f3f3f);
        dist[k]=0;
        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;
            }
            st[t]=true;
            for(int j=1;j<=n;++j){
                dist[j]=Math.min(dist[j],dist[t]+g[t][j]);
            }
        }
        int res=0;
        for(int j=1;j<=n;++j){
            if(dist[j]==0x3f3f3f3f) return -1;
            res=Math.max(res,dist[j]);
        }
        return res;
    }
}


🍸2.到达目的的总方案数


你在一个城市里,城市由 n 个路口组成,路口编号为 0 到 n - 1 ,某些路口之间有 双向 道路。输入保证你可以从任意路口出发到达其他任意路口,且任意两个路口之间最多有一条路。


给你一个整数 n 和二维整数数组 roads ,其中 roads[i] = [ui, vi, timei] 表示在路口 ui 和 vi 之间有一条需要花费 timei 时间才能通过的道路。你想知道花费 最少时间 从路口 0 出发到达路口 n - 1 的方案数。


请返回花费 最少时间 到达目的地的 路径数目 。由于答案可能很大,将结果对 10^9 + 7 取余 后返回。


题目链接:到达目的地的方案数https://leetcode-cn.com/problems/number-of-ways-to-arrive-at-destination/        


       这道题是力扣某一周的周赛题,同样数据范围比较小,所以我们可以使用朴素的Dijkstra,但要注意这道题值的范围很大,所以无穷大值我们不能使用0x3f3f3f3f了。因为是统计到达的方案数,所以我们还需要使用一个cnt数组来统计到达每个位置的方案数,相当于是有点最短路+动态规划的感觉了。


       代码转换:

class Solution {
    int N=210;
    long[][] g=new long[N][N];
    boolean[] st=new boolean[N];
    long[] dist=new long[N];
    long INF = (Long.MAX_VALUE >> 1) - (long)1e5;
    int MOD = (int)1e9 + 7;
    int max=1;
    int[] cnt=new int[N];
    public int countPaths(int n, int[][] roads) {
        for(int i=0;i<n;++i){
          for(int j=0;j<n;++j){
              g[i][j]=INF;
          }
        }
        for(int[] s:roads){
            int a=s[0];
            int b=s[1];
            int w=s[2];
            g[a][b]=g[b][a]=w;
        }
        return Dijkstra(n);
    }
    int Dijkstra(int n){
        Arrays.fill(dist,INF);
        dist[0]=0;
        cnt[0]=1;
        for(int i=0;i<n;++i){
            int t=-1;
            for(int j=0;j<n;++j){
                if(!st[j]&&(t==-1||dist[t]>dist[j])){
                    t=j;
                }
            }
                st[t]=true;
                for(int j=0;j<n;++j){
                    if(dist[t]+g[t][j]<dist[j]){
                        dist[j]=dist[t]+g[t][j];
                        cnt[j]=cnt[t];
                    }else if(dist[t]+g[t][j]==dist[j]){
                        cnt[j]=(cnt[j]+cnt[t])%MOD;
                    }
             }                           
        }
        return cnt[n-1];
    }
}


🍓7.堆优化版Dijkstra


        朴素版的Dijkstra的时间复杂度为O(n^2),所以在点的数量变多时非常容易TLE,因此我们想到对原有的Dijkstra进行优化。


        那我们应该对哪一部分进行优化呢?


       我们有一个每次查找取出距离起点最小值的操作,所以我们可以想到利用优先队列进行优化,每次可以在O(1)的时间复杂度内取出距离起始点最近的点。


       思路过程:


       前面的过程一样,首先我们需要将起点放入优先队列中,然后进行一个while(!queue.isEmpty)的操作,类似BFS算法。每次取出距离最小的点,当然如果该点已经被取出来过那我们就应该continue,原理同朴素Dijkstra一样。然后我们同样使用该点进行相同的操作,去更新其他点的最短距离,每次更新一个点后,我们应该同时将其放入队列,让它继续去更新其他的边,因此最终完成的效率是O(mlogn),m是边数。


      完整代码转换:

import java.util.*;
public class Main {
    static int N=100010;
    static int n,m;
    static int[] dist=new int[N];
    static boolean[] st=new boolean[N];
    //领接表
    static Map<Integer,List<Node>> adj=new HashMap<>();
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        m=sc.nextInt();
        while (m-->0){
            int a=sc.nextInt();
            int b=sc.nextInt();
            int w=sc.nextInt();
            if (!adj.containsKey(a)) adj.put(a,new ArrayList<>());
            adj.get(a).add(new Node(b,w));
        }
        int t=dijkstra();
        System.out.println(t);
    }
    //核心代码
    static int dijkstra(){
        Arrays.fill(dist,0x3f3f3f3f);
        dist[1]=0;
        PriorityQueue<int[]> heap=new PriorityQueue<>((a,b)->a[1]-b[1]);//小顶堆
        heap.offer(new int[]{1,0});
        while (!heap.isEmpty()){
            //每次放出距离最小的点
            int[] t=heap.poll();
            int ver=t[0],distance=t[1];
            //已经遍历过该点,直接跳过
            if (st[ver]) continue;
            st[ver]=true;
            //更新和最小节点相连的点
            List<Node> list=adj.get(ver);
            if (list==null) continue;
            for (Node node:list){
                int idx=node.idx;
                if (dist[idx]>distance+node.d){
                    dist[idx]=distance+node.d;
                    heap.offer(new int[]{idx,dist[idx]});
                }
            }
        }
        return dist[n]==0x3f3f3f3f?-1:dist[n];
    }
}
class Node{
    int idx;
    int d;
    public Node(int idx, int d) {
        this.idx = idx;
        this.d = d;
    }
}

       优化版的Dijkstra习题就没准备了,前面的两题都可以改成堆优化版的Dijkstra,大家也可以自行找习题训练。


相关文章
|
3月前
|
存储 运维 监控
基于 C# 语言的 Dijkstra 算法在局域网内监控软件件中的优化与实现研究
本文针对局域网监控系统中传统Dijkstra算法的性能瓶颈,提出了一种基于优先队列和邻接表优化的改进方案。通过重构数据结构与计算流程,将时间复杂度从O(V²)降至O((V+E)logV),显著提升大规模网络环境下的计算效率与资源利用率。实验表明,优化后算法在包含1000节点、5000链路的网络中,计算时间缩短37.2%,内存占用减少21.5%。该算法适用于网络拓扑发现、异常流量检测、故障定位及负载均衡优化等场景,为智能化局域网监控提供了有效支持。
83 5
|
9天前
|
机器学习/深度学习 编解码 算法
【机器人路径规划】基于迪杰斯特拉算法(Dijkstra)的机器人路径规划(Python代码实现)
【机器人路径规划】基于迪杰斯特拉算法(Dijkstra)的机器人路径规划(Python代码实现)
|
1月前
|
算法 机器人 定位技术
基于机器视觉和Dijkstra算法的平面建筑群地图路线规划matlab仿真
本程序基于机器视觉与Dijkstra算法,实现平面建筑群地图的路径规划。通过MATLAB 2022A读取地图图像,识别障碍物并进行路径搜索,支持鼠标选择起点与终点,最终显示最优路径及长度,适用于智能导航与机器人路径规划场景。
|
11月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
607 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
7月前
|
算法 编译器 C++
【狂热算法篇】探秘图论之Dijkstra 算法:穿越图的迷宫的最短路径力量(通俗易懂版)
【狂热算法篇】探秘图论之Dijkstra 算法:穿越图的迷宫的最短路径力量(通俗易懂版)
|
11月前
|
存储 算法 程序员
迪杰斯特拉(Dijkstra)算法(C/C++)
迪杰斯特拉(Dijkstra)算法(C/C++)
|
机器学习/深度学习 算法 Java
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
这篇文章介绍了基于贪婪技术思想的Prim算法和Dijkstra算法,包括它们的伪代码描述、Java源代码实现、时间效率分析,并展示了算法的测试用例结果,使读者对贪婪技术及其应用有了更深入的理解。
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
|
3天前
|
传感器 机器学习/深度学习 算法
【使用 DSP 滤波器加速速度和位移】使用信号处理算法过滤加速度数据并将其转换为速度和位移研究(Matlab代码实现)
【使用 DSP 滤波器加速速度和位移】使用信号处理算法过滤加速度数据并将其转换为速度和位移研究(Matlab代码实现)
|
4天前
|
传感器 算法 数据挖掘
基于协方差交叉(CI)的多传感器融合算法matlab仿真,对比单传感器和SCC融合
基于协方差交叉(CI)的多传感器融合算法,通过MATLAB仿真对比单传感器、SCC与CI融合在位置/速度估计误差(RMSE)及等概率椭圆上的性能。采用MATLAB2022A实现,结果表明CI融合在未知相关性下仍具鲁棒性,有效降低估计误差。
|
5天前
|
负载均衡 算法 调度
基于遗传算法的新的异构分布式系统任务调度算法研究(Matlab代码实现)
基于遗传算法的新的异构分布式系统任务调度算法研究(Matlab代码实现)
69 11

热门文章

最新文章