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

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

前言

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;
        }
}

最后

我们都有光明的未来

祝大家考研上岸

祝大家工作顺利

祝大家得偿所愿

祝大家如愿以偿

点赞收藏关注哦

相关文章
|
3天前
|
机器学习/深度学习 算法 数据挖掘
【Python机器学习专栏】关联规则学习:Apriori算法详解
【4月更文挑战第30天】Apriori算法是一种用于关联规则学习的经典算法,尤其适用于购物篮分析,以发现商品间的购买关联。该算法基于支持度和置信度指标,通过迭代生成频繁项集并提取满足阈值的规则。Python中可借助mlxtend库实现Apriori,例如处理购物篮数据,设置支持度和置信度阈值,找出相关规则。
|
3天前
|
机器学习/深度学习 算法 前端开发
【Python机器学习专栏】集成学习算法的原理与应用
【4月更文挑战第30天】集成学习通过组合多个基学习器提升预测准确性,广泛应用于分类、回归等问题。主要步骤包括生成基学习器、训练和结合预测结果。算法类型有Bagging(如随机森林)、Boosting(如AdaBoost)和Stacking。Python中可使用scikit-learn实现,如示例代码展示的随机森林分类。集成学习能降低模型方差,缓解过拟合,提高预测性能。
|
16天前
|
机器学习/深度学习 算法 前端开发
Scikit-learn进阶:探索集成学习算法
【4月更文挑战第17天】本文介绍了Scikit-learn中的集成学习算法,包括Bagging(如RandomForest)、Boosting(AdaBoost、GradientBoosting)和Stacking。通过结合多个学习器,集成学习能提高模型性能,减少偏差和方差。文中展示了如何使用Scikit-learn实现这些算法,并提供示例代码,帮助读者理解和应用集成学习提升模型预测准确性。
|
16天前
|
机器学习/深度学习 算法 Python
使用Python实现集成学习算法:Bagging与Boosting
使用Python实现集成学习算法:Bagging与Boosting
21 0
|
17天前
|
算法 安全 数据可视化
python关联规则学习:FP-Growth算法对药品进行“菜篮子”分析
python关联规则学习:FP-Growth算法对药品进行“菜篮子”分析
16 0
|
23天前
|
算法
【算法学习--字符串】(不含KMP算法)
【算法学习--字符串】(不含KMP算法)
|
2月前
|
机器学习/深度学习 算法 数据挖掘
什么是集成学习算法
什么是集成学习算法
35 0
|
12天前
|
机器学习/深度学习 人工智能 算法
基于DCT和扩频的音频水印嵌入提取算法matlab仿真
本文介绍了结合DCT和扩频技术的音频水印算法,用于在不降低音质的情况下嵌入版权信息。在matlab2022a中实现,算法利用DCT进行频域处理,通过扩频增强水印的隐蔽性和抗攻击性。核心程序展示了水印的嵌入与提取过程,包括DCT变换、水印扩频及反变换步骤。该方法有效且专业,未来研究将侧重于提高实用性和安全性。
|
2天前
|
算法 数据安全/隐私保护 计算机视觉
基于DCT变换的彩色图像双重水印嵌入和提取算法matlab仿真
**算法摘要:** - 图形展示:展示灰度与彩色图像水印应用,主辅水印嵌入。 - 软件环境:MATLAB 2022a。 - 算法原理:双重水印,转换至YCbCr/YIQ,仅影响亮度;图像分割为M×N块,DCT变换后嵌入水印。 - 流程概览:两步水印嵌入,每步对应不同图示表示。 - 核心代码未提供。
|
3天前
|
机器学习/深度学习 算法 数据可视化
Matlab决策树、模糊C-均值聚类算法分析高校教师职称学历评分可视化
Matlab决策树、模糊C-均值聚类算法分析高校教师职称学历评分可视化
10 0