算法打卡:第十一章 图论part10

今日收获:Bellman_ford 队列优化算法(又名SPFA),bellman_ford之判断负权回路和单源有限最短路

1. Bellman_ford 队列优化算法(又名SPFA)

题目链接:94. 城市间货物运输 I (kamacoder.com)

思路:上篇文章中Bellman_ford算法是在每一次循环中对所有边进行松弛操作。实际上只需要对上一次更新的节点相连边进行松弛操作,可以使用队列来优化。

方法:

java 复制代码
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        
        // 接收数据
        int n=sc.nextInt();
        int m=sc.nextInt();
        List<List<Edge>> grid=new ArrayList<>(n+1);
        for (int i=0;i<n+1;i++){
            grid.add(new ArrayList<>());
        }
        
        for (int i=0;i<m;i++){
            int s=sc.nextInt();
            int t=sc.nextInt();
            int v=sc.nextInt();
            
            grid.get(s).add(new Edge(s,t,v));
        }
        
        // 初始化minDist
        int[] minDist=new int[n+1];
        Arrays.fill(minDist,Integer.MAX_VALUE);
        minDist[1]=0;
        
        // 存储已更新节点相连的点
        Queue<Integer> queue=new LinkedList<>();
        queue.add(1);
        
        // 判断节点是否已经在队列中
        boolean[] inQueue=new boolean[n+1];
        
        while (!queue.isEmpty()){
            int cur=queue.poll();
            inQueue[cur]=false;
            
            for (Edge edge:grid.get(cur)){
                if (minDist[cur]+edge.val<minDist[edge.to]){
                    minDist[edge.to]=minDist[cur]+edge.val;
                    if (!inQueue[edge.to]){
                        queue.offer(edge.to);
                        inQueue[edge.to]=true;
                    }
                }
            }
        }
        
        if (minDist[n]!=Integer.MAX_VALUE){
            System.out.println(minDist[n]);
        }else {
            System.out.println("unconnected");
        }
    }
}

class Edge{
    int from;
    int to;
    int val;
    
    public Edge(int from,int to,int val){
        this.from=from;
        this.to=to;
        this.val=val;
    }
}

2. bellman_ford之判断负权回路

题目链接:95. 城市间货物运输 II (kamacoder.com)

思路:这道题中出现了负权回路。在没有负权回路的图中,松弛 n 次以上 ,结果不会有变化;但在有负权回路的情况下,如果松弛 n 次,结果就会有变化了,因为有负权回路可以无限最短路径(一直绕圈,就可以一直得到无限小的最短距离)。

(1)如果没有用队列优化,则松弛n次看终点的成本会不会变化

(2)如果用队列优化的版本,假设每个节点和所有的节点相连则有n-1条边,每个节点最多放入队列n-1次。如果有优先队列则存在节点被放入队列n次

方法:

java 复制代码
import java.util.*;
 
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
         
        // 接收数据
        int n=sc.nextInt();
        int m=sc.nextInt();
        List<List<Edge>> grid=new ArrayList<>(n+1);
        for (int i=0;i<n+1;i++){
            grid.add(new ArrayList<>());
        }
         
        for (int i=0;i<m;i++){
            int s=sc.nextInt();
            int t=sc.nextInt();
            int v=sc.nextInt();
             
            grid.get(s).add(new Edge(s,t,v));
        }
         
        // 初始化minDist
        int[] minDist=new int[n+1];
        Arrays.fill(minDist,Integer.MAX_VALUE);
        minDist[1]=0;
         
        // 存储已更新节点相连的点
        Queue<Integer> queue=new LinkedList<>();
        queue.add(1);
         
        // 判断节点是否已经在队列中
        boolean[] inQueue=new boolean[n+1];
        
        // 记录节点加入队列的次数
        int[] count=new int[n+1];
        count[1]++;
        
        // 是否存在负权回路
        boolean flag=false;
         
        while (!queue.isEmpty()){
            int cur=queue.poll();
            inQueue[cur]=false;
             
            for (Edge edge:grid.get(cur)){
                if (minDist[cur]+edge.val<minDist[edge.to]){
                    minDist[edge.to]=minDist[cur]+edge.val;
                    if (!inQueue[edge.to]){
                        queue.offer(edge.to);
                        inQueue[edge.to]=true;
                        count[edge.to]++;
                    }
                    
                    if (count[edge.to]==n){
                        flag=true;
                        while (!queue.isEmpty()){  // 结束内外层循环
                            queue.poll();
                        }
                        break;
                    }
                }
            }
        }
         
        if (flag){
            System.out.println("circle");
            return;
        }
         
        if (minDist[n]!=Integer.MAX_VALUE){
            System.out.println(minDist[n]);
        }else {
            System.out.println("unconnected");
        }
    }
}
 
class Edge{
    int from;
    int to;
    int val;
     
    public Edge(int from,int to,int val){
        this.from=from;
        this.to=to;
        this.val=val;
    }
}

3. bellman_ford之单源有限最短路

题目链接:96. 城市间货物运输 III (kamacoder.com)

思路:因为最多可以经过k个城市,所以对所有边进行k+1次松弛操作。每一次松弛操作都要基于上一次松弛操作的结果(这个目前不明白,先这样写吧,之后填坑。讲解在这里代码随想录

方法:

java 复制代码
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
         
        // 存储边
        List<Edge> edges=new ArrayList<>(m);
        for (int i=0;i<m;i++){
            int s=sc.nextInt();
            int t=sc.nextInt();
            int v=sc.nextInt();
             
            edges.add(new Edge(s,t,v));
        }
        
        int src=sc.nextInt();
        int dst=sc.nextInt();
        int k=sc.nextInt();
         
        // minDist数组和初始化
        int[] minDist=new int[n+1];
        Arrays.fill(minDist,Integer.MAX_VALUE);
        minDist[src]=0;
        
        int[] copy=new int[n+1];
         
        for (int i=0;i<k+1;i++){  // k+1次松弛边
            copy=Arrays.copyOf(minDist,n+1);
            for (Edge edge:edges){
                if (copy[edge.from]!=Integer.MAX_VALUE&&copy[edge.from]+edge.val<minDist[edge.to]){
                    minDist[edge.to]=copy[edge.from]+edge.val;
                }
            }
        }
         
        if (minDist[dst]==Integer.MAX_VALUE){
            System.out.println("unreachable");
        }else {
            System.out.println(minDist[dst]);
        }
    }
}
 
class Edge{
    int from;
    int to;
    int val;
     
    public Edge(int from,int to,int val){
        this.from=from;
        this.to=to;
        this.val=val;
    }
}
相关推荐
XY.散人2 分钟前
初识Linux · 地址空间
linux·算法
进击的_鹏23 分钟前
数据结构之链表(1),单链表
c语言·数据结构·链表
小林up30 分钟前
数据结构与算法笔记7:最小生成树-Prim和Kruskal算法
算法
AnFany30 分钟前
数据结构编程实践20讲(Python版)—02链表
数据结构·python·链表
国通快递驿站30 分钟前
助力企业信息化,开源免费工作流引擎AntFlow推出重榜功能tidb支持,为工作流引擎水平扩展提供无限可能
java·spring boot·spring·开源·tidb·activiti
kill bert1 小时前
第18周 3-过滤器
java
十七算法实验室1 小时前
Matlab实现鲸鱼优化算法优化回声状态网络模型 (WOA-ESN)(附源码)
算法
码农小苏241 小时前
力扣刷题--476. 数字的补数【简单】
数据结构·算法·leetcode
Swxctx1 小时前
Go版数据结构 -【4.1 二叉树】
开发语言·数据结构·golang·go版数据结构
一 乐1 小时前
畅阅读小程序|畅阅读系统|基于java的畅阅读系统小程序设计与实现(源码+数据库+文档)
java·小程序·vue·源码·springboot·阅读小程序