首页 > 编程语言 >代码随想录算法训练营第六十六天 | Bellman_ford 队列优化算法(SPFA)、Bellman_ford之判断负权回路、Bellman_ford之单源有限最短路、复习

代码随想录算法训练营第六十六天 | Bellman_ford 队列优化算法(SPFA)、Bellman_ford之判断负权回路、Bellman_ford之单源有限最短路、复习

时间:2024-07-15 20:56:15浏览次数:14  
标签:val int Bellman ford queue nextInt 算法 minDist new

Bellman_ford 队列优化算法(SPFA)

题目链接:https://kamacoder.com/problempage.php?pid=1152
文档讲解:https://programmercarl.com/kamacoder/0094.%E5%9F%8E%E5%B8%82%E9%97%B4%E8%B4%A7%E7%89%A9%E8%BF%90%E8%BE%93I-SPFA.html

思路

Bellman_ford 算法每次松弛都是对所有边进行松弛。但真正有效的松弛,是基于已经计算过的节点在做的松弛。所以只需要对上一次松弛的时候更新过的节点作为出发节点所连接的边进行松弛就够了。使用队列来记录上次松弛的时候更新过的节点

代码

import java.util.*;
class Edge {
    int to;
    int val;
    Edge(int to, int val) {
        this.to = to;
        this.val = val;
    }
}
class Main{
    public static void main (String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt(), m = in.nextInt();
        int[] minDist = new int[n + 1];
        Arrays.fill(minDist, Integer.MAX_VALUE);
        List<List<Edge>> grid = new ArrayList<>();
        for (int i = 0; i <= n; i++) grid.add(new ArrayList<>());
        for (int i = 0; i < m; i++) {
            int s = in.nextInt(), t = in.nextInt(), val = in.nextInt();
            grid.get(s).add(new Edge(t, val));
        }
        int start = 1, end = n;
        minDist[start] = 0;
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(start);
        while (!queue.isEmpty()) {
            int node = queue.poll();
            for (Edge edge : grid.get(node)) {
                int to = edge.to, price = edge.val;
                if (minDist[to] > minDist[node] + price) {
                    minDist[to] = minDist[node] + price;
                    queue.offer(to);
                }
            }
        }
        System.out.println(minDist[end] == Integer.MAX_VALUE ? "unconnected" : minDist[end]);
    }
}

Bellman_ford之判断负权回路

题目链接:https://kamacoder.com/problempage.php?pid=1153
文档讲解:https://programmercarl.com/kamacoder/0095.%E5%9F%8E%E5%B8%82%E9%97%B4%E8…

思路

在 Bellman_ford 算法中,松弛 n-1 次所有的边 就可以求得 起点到任何节点的最短路径,松弛 n 次以上,minDist数组(记录起到到其他节点的最短距离)中的结果也不会有改变。而本题有负权回路的情况下,一直都会有更短的最短路,所以松弛第n次,minDist数组也会发生改变。那么解决本题的 核心思路,就是在 kama94.城市间货物运输I 的基础上,再多松弛一次,看minDist数组是否发生变化。

代码

import java.util.*;
class Edge {
    int to;
    int val;
    public Edge(int to, int val) {
        this.to = to;
        this.val = val;
    }
}
class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        List<List<Edge>> grid = new ArrayList<>(n + 1);
        for (int i = 0; i < n + 1; i++) {
            grid.add(new LinkedList<>());
        }
        int s, e, v;
        for (int i = 0; i < m; i++) {
            s = scanner.nextInt();
            e = scanner.nextInt();
            v = scanner.nextInt();
            List<Edge> edges = grid.get(s);
            edges.add(new Edge(e, v));
        }
        int[] minDist = new int[n + 1];
        Arrays.fill(minDist, Integer.MAX_VALUE);
        // 记录节点加入队列几次
        int [] visited = new int[n + 1];
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(1);
        visited[1]++;
        // 起始点到自身的距离为0
        minDist[1] = 0;
        while (!queue.isEmpty()) {
            int cur = queue.poll();
            for (Edge edge : grid.get(cur)) {
                int from = cur;
                int to = edge.to;
                int value = edge.val;
                if (minDist[to] > minDist[from] + value) {
                    minDist[to] = minDist[from] + value;
                    queue.offer(to);
                    visited[to]++;
                    if(visited[to] == n){
                        // 如果加入队列次数超过 n-1次 就说明该图与负权回路
                        System.out.print("circle");
                        return;
                    }
                }
            }
        }
        // 不能到达终点
        if (Integer.MAX_VALUE == minDist[n]) {
            System.out.print("unconnected");
        } else {
            // 到达终点最短路径
            System.out.print(minDist[n]);
        }
    }
}

Bellman_ford之单源有限最短路

题目链接:https://kamacoder.com/problempage.php?pid=1154
文档讲解:https://programmercarl.com/kamacoder/0096.%E5%9F%8E%E5%B8%82%E9%97%B4%E8%B4%A7%E7%89%A9%E8…

思路

本题是求:起点最多经过k + 1 条边到达终点的最短距离。对所有边松弛一次,相当于计算起点到达与起点一条边相连的节点的最短距离,那么对所有边松弛 k + 1次,就是求起点到达与起点k + 1条边相连的节点的最短距离。Bellman_ford 标准写法是松弛 n-1 次,本题就松弛 k + 1次就好。

代码

import java.util.*;
class Edge {
        int to;
        int val;
        public Edge(int to, int val) {
            this.to = to;
            this.val = val;
        }
    }
class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();

        List<List<Edge>> grid = new ArrayList<>(n + 1);
        for (int i = 0; i < n + 1; i++) {
            grid.add(new LinkedList<>());
        }
        int s, e, v;
        for (int i = 0; i < m; i++) {
            s = scanner.nextInt();
            e = scanner.nextInt();
            v = scanner.nextInt();
            List<Edge> edges = grid.get(s);
            edges.add(new Edge(e, v));
        }
        
        int src = scanner.nextInt();
        int dst = scanner.nextInt();
        int k = scanner.nextInt();
        k++;

        int[] minDist = new int[n + 1];
        Arrays.fill(minDist, Integer.MAX_VALUE);

        Queue<Integer> queue = new LinkedList<>();
        queue.offer(src);
        minDist[src] = 0;
        // 松弛 k + 1 轮
        while (k-- > 0 && !queue.isEmpty()) {
            boolean [] visited = new boolean[n + 1];
            int [] tmp = minDist.clone(); // 深拷贝 获取上一次计算的结果
            int size = queue.size(); // 记录上次入队列的节点个数
            while (size-- > 0) { // 上一轮松弛入队列的节点,这次对应的边都要做松弛
                int cur = queue.poll();
                for (Edge edge : grid.get(cur)) {
                    int from = cur;
                    int to = edge.to;
                    int value = edge.val;
                    if (minDist[to] > tmp[from] + value) { 
                        minDist[to] = tmp[from] + value;
                        if(visited[to]) continue; 
                        visited[to] = true;
                        queue.offer(to);
                    }
                }
            }
            
        }
        if (Integer.MAX_VALUE == minDist[dst]) {
            System.out.print("unreachable");
        } else {
            System.out.print(minDist[dst]);
        }

    }
}

复习二叉树部分

530.二叉搜索树的最小绝对差
501.二叉搜索树中的众数
236. 二叉树的最近公共祖先

标签:val,int,Bellman,ford,queue,nextInt,算法,minDist,new
From: https://blog.csdn.net/Danny_8/article/details/140404922

相关文章

  • 代码随想录算法训练营第六十五天 | dijkstra(堆优化版)精讲、Bellman_ford 算法精讲、复
    dijkstra(堆优化版)精讲—卡码网:47.参加科学大会题目链接:https://kamacoder.com/problempage.php?pid=1047文档讲解:https://programmercarl.com/kamacoder/0047.%E5%8F%82%E4%BC%9Adijkstra%E5%A0%86.html思路当节点数多,边数少(稀疏图)时,可以考虑从边的角度出发,用堆来......
  • 【Unity】凸包算法对比及实现
    背景在做闵可夫斯基差的可视化的时候,获得了很多个点,想要知道其是否包含原点,需要连接一个包裹这些点的最小凸多边形。因此就单独研究了这个部分,实现了功能并进行分析对比。凸包算法可以在多个散落的点中找到最小能包裹它的外壳,像套上一个橡皮筋一样。这里主要采用Graham算法进行代......
  • Vue--DIFF 算法
    一、什么是DIFF算法?DIFF算法用于比较两棵虚拟DOM树的差异,从而生成最小化的DOM更新操作。这个过程通常分为以下几个步骤:树形结构的对比:逐层对比新旧虚拟DOM树,找出差异节点。最小化更新:对实际DOM进行最小量的修改,以反映虚拟DOM的变化。二、Vue的DIFF算法原理......
  • 单链表算法 - 链表的中间节点
    .-力扣(LeetCode).-备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界IT名企DreamOffer。https://leetcode.cn/problems/middle-of-the-linked-list/description/思路1: 思路2:代码:/***Definitionforsingly-linkedlist.*struct......
  • 多源谱修复学习算法(Multi-source Spectral Repair Learning Algorithm, MSRL)
    多源谱修复学习算法(Multi-sourceSpectralRepairLearningAlgorithm,MSRL)是一种针对非完备多源数据的处理方法,旨在解决因数据缺失而导致的多源数据学习问题。非完备多源数据是指在数据采集过程中,由于各种原因(如数据源多样性带来的质量差异或数据获取能力限制),导致某些样......
  • 多源谱嵌入融合学习算法(Multi-source Spectral Embedding Fusion Learning Algorithm,
    多源谱嵌入融合学习算法(Multi-sourceSpectralEmbeddingFusionLearningAlgorithm,简称MSEF)是一种专门设计用于处理多源数据的高级学习方法,其目标是在不同数据源之间建立一致的表示,从而提高聚类性能和数据理解的全面性。这种算法的核心在于利用全局和局部谱嵌入的融合,以......
  • 启发式算法(Heuristic Algorithm)
    启发式算法(HeuristicAlgorithm)是一类用于解决复杂问题的算法,通过利用问题的某些特征和经验规则,在可接受的时间范围内找到较好的近似解。启发式算法不保证找到最优解,但通常可以在合理的计算时间内获得可行且质量较高的解。启发式算法的思想启发式算法的核心思想是通过利用......
  • 分布式中唯一ID生成算法
    前言分布式系统中,难免会需要生成唯一ID作为标识符的需求。数据库主键,订单系统,日志系统,消息队列,会话管理,当并发量巨大且需要唯一标识信息的ID时,唯一ID生成算法就显得非常重要。UUIDUUID(UniversallyUniqueIdentifier,通用唯一标识符)是一种标准化的唯一标识符生成算法,它能够在全......
  • 「代码随想录算法训练营」第十一天 | 二叉树 part1
    二叉树的基本知识链接:https://programmercarl.com/二叉树理论基础.html要点:深度优先遍历前序遍历(递归法,迭代法)中序遍历(递归法,迭代法)后序遍历(递归法,迭代法)广度优先遍历层次遍历(迭代法)由于栈就是递归的一种实现结构,因此前中后序遍历的逻辑可以借助栈使用递归的方式......
  • 数据结构的基础(集合框架算法,复杂度和泛型)
    一.什么是集合框架        Java集合框架JavaCollectionFramework,又被称为容器container,是定义在java.util包下的一组接口interfaces和其实现类classes。        其主要表现为将多个元素element置于一个单元中,用于对这些元素进行......