零基础学算法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月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
99 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
3月前
|
存储 算法 程序员
迪杰斯特拉(Dijkstra)算法(C/C++)
迪杰斯特拉(Dijkstra)算法(C/C++)
|
5月前
|
机器学习/深度学习 算法 Java
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
这篇文章介绍了基于贪婪技术思想的Prim算法和Dijkstra算法,包括它们的伪代码描述、Java源代码实现、时间效率分析,并展示了算法的测试用例结果,使读者对贪婪技术及其应用有了更深入的理解。
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
|
5月前
|
算法
路径规划算法 - 求解最短路径 - Dijkstra(迪杰斯特拉)算法
路径规划算法 - 求解最短路径 - Dijkstra(迪杰斯特拉)算法
115 0
|
6月前
|
算法
基于Dijkstra算法的最优行驶路线搜索matlab仿真,以实际城市复杂路线为例进行测试
使用MATLAB2022a实现的Dijkstra算法在城市地图上搜索最优行驶路线的仿真。用户通过鼠标点击设定起点和终点,算法规划路径并显示长度。测试显示,尽管在某些复杂情况下计算路径可能与实际有偏差,但多数场景下Dijkstra算法能找到接近最短路径。核心代码包括图的显示、用户交互及Dijkstra算法实现。算法基于图论,不断更新未访问节点的最短路径。测试结果证明其在简单路线及多数复杂城市路况下表现良好,但在交通拥堵等特殊情况下需结合其他数据提升准确性。
|
6月前
|
资源调度 算法 定位技术
|
6月前
|
算法 Java C++
《经典图论算法》迪杰斯特拉算法(Dijkstra)
这个是求最短路径的迪杰斯特拉算法,另外我还写了50多种《经典图论算法》,每种都使用C++和Java两种语言实现,熟练掌握之后无论是参加蓝桥杯,信奥赛,还是其他比赛,或者是面试,都能轻松应对。
|
8天前
|
机器学习/深度学习 算法
基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真
本项目基于改进遗传优化的BP神经网络进行金融序列预测,使用MATLAB2022A实现。通过对比BP神经网络、遗传优化BP神经网络及改进遗传优化BP神经网络,展示了三者的误差和预测曲线差异。核心程序结合遗传算法(GA)与BP神经网络,利用GA优化BP网络的初始权重和阈值,提高预测精度。GA通过选择、交叉、变异操作迭代优化,防止局部收敛,增强模型对金融市场复杂性和不确定性的适应能力。
133 80
|
1天前
|
机器学习/深度学习 算法
基于遗传优化的双BP神经网络金融序列预测算法matlab仿真
本项目基于遗传优化的双BP神经网络实现金融序列预测,使用MATLAB2022A进行仿真。算法通过两个初始学习率不同的BP神经网络(e1, e2)协同工作,结合遗传算法优化,提高预测精度。实验展示了三个算法的误差对比结果,验证了该方法的有效性。
|
4天前
|
机器学习/深度学习 数据采集 算法
基于PSO粒子群优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
本项目展示了基于PSO优化的CNN-GRU-SAM网络在时间序列预测中的应用。算法通过卷积层、GRU层、自注意力机制层提取特征,结合粒子群优化提升预测准确性。完整程序运行效果无水印,提供Matlab2022a版本代码,含详细中文注释和操作视频。适用于金融市场、气象预报等领域,有效处理非线性数据,提高预测稳定性和效率。

热门文章

最新文章