单源最短路径【学习算法】

简介: 单源最短路径【学习算法】

前言

2023-8-14 18:21:41

以下内容源自《【学习算法】》

仅供学习交流使用

版权

禁止其他平台发布时删除以下此话

本文首次发布于CSDN平台

作者是CSDN@日星月云

博客主页是https://blog.csdn.net/qq_51625007

禁止其他平台发布时删除以上此话

推荐

第七章 图【数据结构与算法】

单源最短路径

Java算法实现

代码

import java.util.*;
/**
 * 在这个代码模板中,我们通过遍历int[] paths来构建图的邻接表。
 * 每个元素paths[i]表示从顶点paths[i][0]到顶点paths[i][1]的距离为paths[i][2]。
 *
 * 我们使用一个ArrayList来表示图的邻接表,每个顶点都有一个对应的列表,其中存储了与该顶点相连的边的目标顶点及其权重。
 *
 * 然后,我们可以使用Dijkstra算法来计算从给定起始顶点到其他顶点的最短距离。
 * 算法的时间复杂度为O((V+E)logV),其中V为顶点的数量,E为边的数量。
 *
 * 这个代码模板使用了优先队列来实现最小堆,以提高算法的效率。算法的时间复杂度为O(ElogV),其中E为边的数量,V为顶点的数量。
 */
public class Dijkstra {
    public static void main(String[] args) {
        //
        int[][] paths = {{0, 1, 2}, {0, 2, 4}, {1, 2, 1}, {1, 3, 4}, {1, 4, 2}, {2, 4, 3}, {3, 5, 2}, {4, 3, 3}, {4, 5, 2}};
        int n = 6;
        int[] dist = dijkstra(paths, n, 0);
        System.out.println(Arrays.toString(dist));
        int distD = dijkstraD(paths, n, 0,n-1);
        System.out.println(distD);
    }
    public static int[] dijkstra(int[][] paths, int n, int start) {
        //邻接表
        List<int[]>[] graph = new ArrayList[n];
        //初始化
        for (int i = 0; i < n; i++) {
            graph[i] = new ArrayList<>();
        }
        //初始化
        for (int[] path : paths) {
            int source = path[0];
            int destination = path[1];
            int weight = path[2];
            graph[source].add(new int[]{destination, weight});
            graph[destination].add(new int[]{source, weight});
        }
        //距离
        int[] dist = new int[n];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[start] = 0;
        //优先队列
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] - b[1]);
        //表示到达顶点 最小距离
        pq.offer(new int[]{start, 0});
        while (!pq.isEmpty()) {
            //取出
            int[] curr = pq.poll();
            int vertex = curr[0];
            int distance = curr[1];
            //跳过
            if (distance > dist[vertex]) {
                continue;
            }
            //更新
            for (int[] edge : graph[vertex]) {
                int newDistance = distance + edge[1];
                if (newDistance < dist[edge[0]]) {
                    dist[edge[0]] = newDistance;
                    pq.offer(new int[]{edge[0], newDistance});
                }
            }
        }
        return dist;
    }
    public static int dijkstraD(int[][] paths,int n, int start,int end) {
        //邻接表
        List<int[]>[] graph = new ArrayList[n];
        //初始化
        for (int i = 0; i < n; i++) {
            graph[i] = new ArrayList<>();
        }
        //初始化
        for (int[] path : paths) {
            int source = path[0];
            int destination = path[1];
            int weight = path[2];
            graph[source].add(new int[]{destination, weight});
            graph[destination].add(new int[]{source, weight});
        }
        //距离
        int[] dist = new int[n];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[start] = 0;
        //优先队列
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] - b[1]);
        //表示到达顶点 最小距离
        pq.offer(new int[]{start, 0});
        while (!pq.isEmpty()) {
            int[] curr = pq.poll();
            int vertex = curr[0];
            int distance = curr[1];
            if (distance > dist[vertex]) {
                continue;
            }
            if (vertex==end){
                return distance;
            }
            for (int[] edge : graph[vertex]) {
                int newDistance = distance + edge[1];
                if (newDistance < dist[edge[0]]) {
                    dist[edge[0]] = newDistance;
                    pq.offer(new int[]{edge[0], newDistance});
                }
            }
        }
        return dist[end];
    }
}

结果

[0, 2, 3, 6, 4, 6]
6

带限制的单源最短路径

1928. 规定时间内到达终点的最小花费

1928. 规定时间内到达终点的最小花费

class Solution {
    /*
        带限制的最短路径操作
        其实就是最短路径算法的变化版本,这里带限制的条件使得我们在向对应的队列加入元素的时候需要进行一定的判断,
        只有能够帮助我们的答案达到更优的操作才能够加入到队列当中,否则就会由于加入过多的元素导致最终超时。
        作者:豆小科
        链接:https://leetcode.cn/problems/minimum-cost-to-reach-destination-in-time/solutions/2224593/dai-xian-zhi-de-zui-duan-lu-jing-cao-zuo-d7t6/
        来源:力扣(LeetCode)
        著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
     */
   public static int minCost(int maxTime, int[][] edges, int[] passingFees) {
        // 使用最短路径进行处理
        int n = passingFees.length;
        //构造图邻接表
        List<List<int[]>> graph = new ArrayList<>();
        for (int i = 0; i < n; i++) graph.add(new ArrayList<>());
        for (int[] edge : edges) {
            int x = edge[0];
            int y = edge[1];
            int time = edge[2];
            graph.get(x).add(new int[]{y, time});
            graph.get(y).add(new int[]{x, time});
        }
        //优先队列
        PriorityQueue<int[]> queue = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
        //时间 花费 当前结点
        queue.add(new int[]{0, passingFees[0], 0});
        //到达node的最少时间
        Map<Integer, Integer> timeMap = new HashMap<>();
        while (!queue.isEmpty()) {
            int[] poll = queue.poll();
            int time = poll[0];
            int ct = poll[1];
            int node = poll[2];
            //继续
            if (time > maxTime) continue;
            //结束
            if (node == n - 1) return ct;
            //更新
            if (!timeMap.containsKey(node) || timeMap.get(node) > time) {
                timeMap.put(node, time);
                for (int[] e : graph.get(node)) {
                    queue.add(new int[]{e[1] + time, passingFees[e[0]] + ct, e[0]});
                }
            }
        }
        return -1;
    }
}

LCP 35. 电动车游城市

LCP 35. 电动车游城市

    /**
     * 首先建图, 存储每个城市相邻的城市和距离
     *
     * 使用一个二维数组保存结果arr[i][j] = k, i = 所在城市, j = 剩余电量, k = 最短时间
     *
     * 用队列来记录每个路径的信息 {time,cur,power}, time = 已用时间, cur = 所在城市, power = 剩余电量 (使用优先队列来保证每次优先执行已用时间最少的路径)
     *
     * 每次只会有两种操作
     *
     * 充一次电 - 新时间 = 已用时间 + 当前城市每单位充电需要时间, 新电量 = 剩余电量 + 1
     * 去往下一个城市 - 新时间 = 已用时间 + 去往该需要消耗的时间, 新电量 = 剩余电量 − 去往该城市需要消耗的电量
     *
     * 作者:Feilulue 🍒
     * 链接:https://leetcode.cn/problems/DFPeFJ/solutions/974051/java-dijkstra-by-feilue-8p14/
     * 来源:力扣(LeetCode)
     * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
     */
class Solution {
        public int electricCarPlan(int[][] paths, int cnt, int start, int end, int[] charge) {
            int n = charge.length;
            //构造了图
            List<int[]>[] map = new List[n];
            for(int i = 0; i < n; i++) map[i] = new ArrayList();
            for(int[] path : paths){
                map[path[0]].add(new int[]{path[1], path[2]});
                map[path[1]].add(new int[]{path[0], path[2]});
            }
            //使用一个二维数组保存结果arr[i][j] = k
            //i = 所在城市, j = 剩余电量, k = 最短时间
            int[][] res = new int[n][cnt+1];
            for(int[] i : res) Arrays.fill(i, Integer.MAX_VALUE/2);
            res[start][0] = 0;
            //用队列来记录每个路径的信息 {time,cur,power},
            //time = 已用时间, cur = 所在城市, power = 剩余电量
            //(使用优先队列来保证每次优先执行已用时间最少的路径)
            Queue<int[]> queue = new PriorityQueue<int[]>((x, y) -> (x[0] - y[0]));
            queue.offer(new int[]{0, start, 0});
            while(!queue.isEmpty()){
                //取出来
                int[] arr = queue.poll();
                int time = arr[0];
                int cur = arr[1];
                int power = arr[2];
                //继续
                if(time > res[cur][power]) continue;
                //结束
                if(cur == end) return time;
                //充一次电
                //新时间 = 已用时间 + 当前城市每单位充电需要时间, 新电量 = 剩余电量 + 1
                if(power < cnt){
                    int t = time + charge[cur];
                    if(t < res[cur][power+1]){
                        res[cur][power+1] = t;
                        queue.offer(new int[]{t, cur, power+1});
                    }
                }
                //去往下一个城市
                //新时间 = 已用时间 + 去往该需要消耗的时间, 新电量 = 剩余电量 − 去往该城市需要消耗的电量
                for(int[] path : map[cur]){
                    int next = path[0];
                    int cost = path[1];
                    int t = time + cost;
                    int p = power - cost;
                    if(p >= 0 && t < res[next][p]){
                        res[next][p] = t;
                        queue.offer(new int[]{t, next, p});
                    }
                }
            }
            return -1;
        }
}

最后

我们都有光明的未来

祝大家考研上岸

祝大家工作顺利

祝大家得偿所愿

祝大家如愿以偿

点赞收藏关注哦

相关文章
|
1月前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
数据结构与算法系列学习之串的定义和基本操作、串的储存结构、基本操作的实现、朴素模式匹配算法、KMP算法等代码举例及图解说明;【含常见的报错问题及其对应的解决方法】你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
【EMNLP2024】基于多轮课程学习的大语言模型蒸馏算法 TAPIR
阿里云人工智能平台 PAI 与复旦大学王鹏教授团队合作,在自然语言处理顶级会议 EMNLP 2024 上发表论文《Distilling Instruction-following Abilities of Large Language Models with Task-aware Curriculum Planning》。
|
1月前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习(8)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之王道第2.3章节之线性表精题汇总二(5)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
IKU达人之数据结构与算法系列学习×单双链表精题详解、数据结构、C++、排序算法、java 、动态规划 你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
2天前
|
机器学习/深度学习 算法
基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真
本项目基于改进遗传优化的BP神经网络进行金融序列预测,使用MATLAB2022A实现。通过对比BP神经网络、遗传优化BP神经网络及改进遗传优化BP神经网络,展示了三者的误差和预测曲线差异。核心程序结合遗传算法(GA)与BP神经网络,利用GA优化BP网络的初始权重和阈值,提高预测精度。GA通过选择、交叉、变异操作迭代优化,防止局部收敛,增强模型对金融市场复杂性和不确定性的适应能力。
105 80
|
21天前
|
算法
基于WOA算法的SVDD参数寻优matlab仿真
该程序利用鲸鱼优化算法(WOA)对支持向量数据描述(SVDD)模型的参数进行优化,以提高数据分类的准确性。通过MATLAB2022A实现,展示了不同信噪比(SNR)下模型的分类误差。WOA通过模拟鲸鱼捕食行为,动态调整SVDD参数,如惩罚因子C和核函数参数γ,以寻找最优参数组合,增强模型的鲁棒性和泛化能力。
|
7天前
|
供应链 算法 调度
排队算法的matlab仿真,带GUI界面
该程序使用MATLAB 2022A版本实现排队算法的仿真,并带有GUI界面。程序支持单队列单服务台、单队列多服务台和多队列多服务台三种排队方式。核心函数`func_mms2`通过模拟到达时间和服务时间,计算阻塞率和利用率。排队论研究系统中顾客和服务台的交互行为,广泛应用于通信网络、生产调度和服务行业等领域,旨在优化系统性能,减少等待时间,提高资源利用率。