当前位置: 首页 > article >正文

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

今日收获:拓扑排序,dijkstra算法

算法讲解部分均来源于代码随想录

1. 拓扑排序

基础知识:

(1)应用场景:给出有向图,将有向图转换为线性的排序就叫拓扑排序(如果图中有环则存在循环依赖,不能做线性排序,所以拓扑排序也可以用来判断有向图中是否有环)

(2)解法:卡恩算法(BFS广度优先搜索)

(3)步骤:

  • 找到入度为0的点加入结果集
  • 将该节点从图中移除

(4)图中有环:此时找不到入度为0的点,所以结果集的长度小于节点个数

题目链接:117. 软件构建 (kamacoder.com)

方法:

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();
        
        // 记录节点的入度
        int[] inDegree=new int[N];
        // 记录依赖关系
        List<List<Integer>> edges=new ArrayList<>(N);
        for (int i=0;i<N;i++){
            edges.add(new ArrayList<>());
        }
        
        
        // 接收依赖关系
        for (int i=0;i<M;i++){
            int s=sc.nextInt();
            int t=sc.nextInt();
            
            edges.get(s).add(t);  // 依赖于s的边
            inDegree[t]++;
        }
        
        // 队列存储入度为0的节点
        Queue<Integer> queue=new LinkedList<>();
        for (int i=0;i<N;i++){
            if (inDegree[i]==0){
                queue.offer(i);
            }
        }
        
        // 存储结果
        List<Integer> result=new ArrayList<>();
        while (!queue.isEmpty()){
            int cur=queue.poll();
            result.add(cur);
            
            // 将相连节点的入度减一
            for (int edge:edges.get(cur)){
                inDegree[edge]--;
                if (inDegree[edge]==0){
                    queue.offer(edge);
                }
            }
        }
        
        // 判断是否存在环
        if (result.size()==N){
            for (int i=0;i<result.size()-1;i++){
                System.out.print(result.get(i)+" ");
            }
            System.out.print(result.get(N-1));
        }else {
             System.out.println(-1);
        }
    }
}

2. dijkstra算法

基础知识:

(1)求最短路径问题:给出有向图,求起点到终点的最短路径。

(2)dijkstra算法:有向图中边的权值均为非负数;可以求起点到其他节点的最短路径算法

(3)dijkstra三部曲:minDist数组用来记录每一个节点距离源点的最小距离。

  • 第一步,选源点到哪个节点近且该节点未被访问过
  • 第二步,该最近节点被标记访问过
  • 第三步,更新非访问节点到源点的距离(即更新minDist数组)

(4)如果需要打印边,和prim算法一样,在更新minDist数组时记录父节点

(5)和prim算法的区别:

  • prim是求非访问节点到最小生成树的最小距离
  • dijkstra是求非访问节点到源点的最小距离,源点是固定的

(6)要求非负权值是因为,此算法后续节点距离源节点的距离=前面节点到源节点的距离+本边的权值,后面的节点一定要比前面已加入路径中的节点成本大

题目链接:47. 参加科学大会(第六期模拟笔试) (kamacoder.com)

方法:

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();
        
        boolean[] visited=new boolean[N+1]; // 记录是否访问
        int[][] grid=new int[N+1][N+1];  // 记录所有的边,初始化为不可达
        for(int i=0;i<N+1;i++){
            Arrays.fill(grid[i],Integer.MAX_VALUE);
        }
        
        for (int i=0;i<M;i++){
            int s=sc.nextInt();
            int e=sc.nextInt();
            int v=sc.nextInt();
            
            grid[s][e]=v;
        }
        
        int[] minDist=new int[N+1];  // 其他点到源点的最小距离
        for (int i=0;i<N+1;i++){
            minDist[i]=Integer.MAX_VALUE;
        }
        minDist[1]=0;
        
        // 求到原点的最小距离
        for (int i=1;i<N+1;i++){
            int cur=-1;
            int minD=Integer.MAX_VALUE;
            
            // 选择最小节点
            for (int j=1;j<N+1;j++){
                if (minDist[j]<minD&&!visited[j]){
                    cur=j;
                    minD=minDist[j];
                }
            }
            
            if (cur==-1){
                break;
            }
            // 标记访问
            visited[cur]=true;
            
            // 更新其他节点
            for (int j=1;j<N+1;j++){
                if (minDist[cur]+grid[cur][j]<minDist[j]&&!visited[j]&&grid[cur][j]!=Integer.MAX_VALUE){
                    minDist[j]=minDist[cur]+grid[cur][j];
                }
            }
        }
        
        if (minDist[N]==Integer.MAX_VALUE){
            System.out.println(-1);
        }else {
            System.out.println(minDist[N]);
        }
    }
}

http://www.kler.cn/a/323398.html

相关文章:

  • 整数唯一分解定理
  • 使用Java绘制图片边框,解决微信小程序map组件中marker与label层级关系问题,label增加外边框后显示不能置与marker上面
  • JMeter与大模型融合应用之JMeter日志分析服务化实战应用
  • (一)Ubuntu20.04服务器端部署Stable-Diffusion-webui AI绘画环境
  • 【Framework系列】UnityEditor调用外部程序详解
  • 北京大学c++程序设计听课笔记101
  • 什么是算力?cpu+显卡吗?
  • 【JAVA-数据结构】时间和空间复杂度
  • ubuntu中通过源码安装pointnet2_ops_lib
  • 360周鸿祎为什么说大模型已成茶叶蛋?
  • html+css+js实现Progress 进度条
  • 差速轮纯跟踪算法
  • 设备管理平台-支持快速开发
  • Woocommerce怎么分类显示产品?如何将Shopify的产品导入到Woocommerce?
  • 如何恢复被删除的 GitLab 项目?
  • git rebase 调整提交顺序
  • springboot 实现用户登录身份验证
  • 【NLP】daydayup 词向量训练模型word2vec
  • Maven中 <parent > 的<version>可以使用变量吗
  • Unity3D入门(四) : Android和Unity3D交互 - Unity调用Android
  • FreeRTOS 内存管理源码解析
  • 数据结构:线性表的链式表示
  • 中国农业银行——开源软件一体化管理平台
  • 《AI办公类工具表格处理系列之一——办公小浣熊》
  • 逃离陷阱:如何巧妙避免机器学习中的过拟合与欠拟合
  • 【分布式微服务云原生】K8s(Kubernetes)基本概念和使用方法