代码随想录算法训练营Day55 | 图论理论基础、深度优先搜索理论基础、卡玛网 98.所有可达路径、797. 所有可能的路径、广度优先搜索理论基础

目录

图论理论基础

深度优先搜索理论基础

卡玛网 98.所有可达路径

广度优先搜索理论基础

图论理论基础

图论理论基础 | 代码随想录

图的基本概念

图的种类

大体分为有向图和无向图。

图中的边有方向的是有向图:

img

图中的边没有方向的是无向图:

img

图中的边有权值的是加权图:

img

无向图中的节点的度数表示有几条边连接该节点。

如下图中节点4的度为5,节点6的度为3:

img

有向图中的节点有出度和入度,出度为从该节点出发的边的个数,入度为指向该节点的边的个数。

如下图中节点3的入度为2,出度为1,节点1的入度为0,出度为2:

img

连通性

连通性表示图中节点的连通情况。

连通图

无向图中,任何两个节点都可以到达的图叫做连通图

img

如果有节点不能到达其它节点,则为非连通图:

img

强连通图

有向图中任何两个节点都可以相互到达的图叫做强连通图

img

连通分量

无向图中的极大连通子图称之为该图的一个连通分量

img

图中的节点1、2、5与节点3、4、6构成的两个子图就是该无向图中的两个连通分量,该子图所有节点都是相互可达到的。

强连通分量

有向图中的极大强连通子图称之为该图的强连通分量

img

图中节点1、2、3、4、5构成的子图是强连通分量,节点6、7、8构成的子图不是强连通分量

图的构造

邻接矩阵

邻接矩阵使用二维数组来表示图结构。 邻接矩阵是从节点的角度来表示图,数组大小与节点数相同。

有向图:grid[2][5] = 6,表示 节点 2 连接 节点5 为有向图,节点2 指向 节点5,边的权值为6。

无向图:grid[2][5] = 6, grid[5][2] = 6,表示节点2 与 节点5 相互连通,权值为6。

如图:

img

优点:

  • 表达方式简单,易于理解
  • 检查任意两个节点间是否存在边的操作很快
  • 适合稠密图,在边数接近顶点数平方的图中,邻接矩阵是一种空间效率较高的表示方法。

缺点:

  • 遇到稀疏图,会导致申请过大的二维数组造成空间浪费,且遍历边的时候需要遍历整个 n * n 矩阵,造成时间浪费
邻接表

邻接表使用数组 + 链表的方式来表示图结构。邻接表是从边的数量来表示图,链表大小与边的数量相同。

img

  • 节点1 指向 节点3 和 节点5
  • 节点2 指向 节点4、节点3、节点5
  • 节点3 指向 节点4
  • 节点4指向节点1

优点:

  • 对于稀疏图的存储,只需要存储边,空间利用率高
  • 遍历节点连接情况相对容易

缺点:

  • 检查任意两个节点间是否存在边,效率相对低,需要 O(V)时间,V表示某节点连接其他节点的数量。
  • 实现相对复杂,不易理解

图的遍历

  • 深度优先搜索(DFS)
  • 广度优先搜索(BFS)

深度优先搜索理论基础

深度优先搜索理论基础 | 代码随想录

DFS 的关键是沿着一个方向搜索结果,直到无法继续搜索时再回溯换一个方向搜索。

代码框架:

void dfs(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本节点所连接的其他节点) {
        处理节点;
        dfs(图,选择的节点); // 递归
        回溯,撤销处理结果
    }
}

卡玛网 98.所有可达路径

题目

98. 所有可达路径

思路

代码随想录:98.所有可达路径

图的存储:

  1. 邻接矩阵:

            Scanner scanner = new Scanner(System.in);
            int N = scanner.nextInt();
            int M = scanner.nextInt();
            int[][] graph = new int[N + 1][N + 1];
            for (int i = 0; i < M; i++) {
                int a = scanner.nextInt();
                int b = scanner.nextInt();
                graph[a][b] = 1;
            }
    
  2. 邻接表

            Scanner scanner = new Scanner(System.in);
            int N = scanner.nextInt();
            int M = scanner.nextInt();
            List<LinkedList<Integer>> graph = new ArrayList<>(N + 1);
            for (int i = 0; i <= N; i++) {
                graph.add(new LinkedList<>());
            }
            for (int i = 0; i < M; i++) {
                int a = scanner.nextInt();
                int b = scanner.nextInt();
                graph.get(a).add(b);
            }
    

打印结果:

        //输出结果,注意最后一个数字不添加空格,但是要换行
        for (List<Integer> list : res) {
            for (int i = 0; i < list.size() - 1; i++) {
                System.out.print(list.get(i) + " ");
            }
            System.out.println(list.get(list.size() - 1));
        }

题解

邻接矩阵:

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int N = scanner.nextInt();
        int M = scanner.nextInt();
        // 下标与题目输入保持一致
        int[][] graph = new int[N + 1][N + 1];
        // 初始化邻接矩阵
        for (int i = 0; i < M; i++) {
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            graph[a][b] = 1;
        }
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        // 起点为1
        path.add(1);
        dfs(res, path, graph, 1);
        if (res.isEmpty())
            System.out.println(-1);
        //输出结果,注意最后一个数字不添加空格,但是要换行
        for (List<Integer> list : res) {
            for (int i = 0; i < list.size() - 1; i++) {
                System.out.print(list.get(i) + " ");
            }
            System.out.println(list.get(list.size() - 1));
        }
    }

    static void dfs(List<List<Integer>> res, List<Integer> path, int[][] graph, int index) {
        if (index == graph.length - 1) {
            res.add(new ArrayList<>(path));
            return;
        }
        for (int i = 1; i < graph.length; i++) {
            if (graph[index][i] == 1) {
                path.add(i);
                dfs(res, path, graph, i);
                path.remove(path.size() - 1);
            }
        }
    }
}

邻接表:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int N = scanner.nextInt();
        int M = scanner.nextInt();
        // 下标与题目输入保持一致
        List<LinkedList<Integer>> graph = new ArrayList<>(N + 1);
        // 初始化邻接表
        for (int i = 0; i <= N; i++) {
            graph.add(new LinkedList<>());
        }
        for (int i = 0; i < M; i++) {
            int a = scanner.nextInt();
            int b = scanner.nextInt();
            graph.get(a).add(b);
        }
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        // 起点为1
        path.add(1);
        dfs(res, path, graph, 1);
        if (res.isEmpty())
            System.out.println(-1);
        //输出结果,注意最后一个数字不添加空格,但是要换行
        for (List<Integer> list : res) {
            for (int i = 0; i < list.size() - 1; i++) {
                System.out.print(list.get(i) + " ");
            }
            System.out.println(list.get(list.size() - 1));
        }
    }

    static void dfs(List<List<Integer>> res, List<Integer> path, List<LinkedList<Integer>> graph, int index) {
        if (index == graph.size() - 1) {
            res.add(new ArrayList<>(path));
            return;
        }
        for (int i : graph.get(index)) {
            path.add(i);
            dfs(res, path, graph, i);
            path.remove(path.size() - 1);
        }
    }
}

797. 所有可能的路径

题目

797. 所有可能的路径 - 力扣(LeetCode)

给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序

graph[i] 是一个从节点 i 可以访问的所有节点的列表(即从节点 i 到节点 graph[i][j]存在一条有向边)。

示例 1:

在这里插入图片描述

输入:graph = [[1,2],[3],[3],[]]
输出:[[0,1,3],[0,2,3]]
解释:有两条路径 0 -> 1 -> 3 和 0 -> 2 -> 3

示例 2:

在这里插入图片描述

输入:graph = [[4,3,1],[3,2,4],[3],[4],[]]
输出:[[0,4],[0,3,4],[0,1,3,4],[0,1,2,3,4],[0,1,4]]

提示:

  • n == graph.length
  • 2 <= n <= 15
  • 0 <= graph[i][j] < n
  • graph[i][j] != i(即不存在自环)
  • graph[i] 中的所有元素 互不相同
  • 保证输入为 有向无环图(DAG)
思路

在遍历之前先将 0 号几点加入路径。

由于本题的图为有向无环图(DAG),搜索过程中不会反复遍历同一个点,所以无需判断当前点是否遍历过。

题解
class Solution {
    List<List<Integer>> res = new ArrayList<>();
    List<Integer> path = new ArrayList<>();

    public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
        path.add(0);
        dfs(graph, 0);
        return res;
    }

    void dfs(int[][] graph, int index) {
        if (index == graph.length - 1) {
            res.add(new ArrayList<>(path));
            return;
        }
        for (int neighbor : graph[index]) {
            path.add(neighbor);
            dfs(graph, neighbor);
            path.remove(path.size() - 1);
        }
    }
}

广度优先搜索理论基础

广度优先搜索理论基础 | 代码随想录

BFS 是从起点开始一圈一圈进行搜索的过程,如图:

图三

选择使用队列作为容器。

模板代码:

    // 表示四个方向,分别是右、下、左、上
    private static final int[][] DIR = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};

    // grid 是地图,也就是一个二维数组
    // visited 标记访问过的节点,不要重复访问
    // x, y 表示开始搜索节点的下标
    public static void bfs(char[][] grid, boolean[][] visited, int x, int y) {
        Queue<int[]> queue = new LinkedList<>(); // 定义队列
        queue.add(new int[]{x, y}); // 起始节点加入队列
        visited[x][y] = true; // 只要加入队列,立刻标记为访问过的节点

        while (!queue.isEmpty()) { // 开始遍历队列里的元素
            int[] cur = queue.poll(); // 从队列取元素
            int curx = cur[0];
            int cury = cur[1]; // 当前节点坐标

            for (int i = 0; i < 4; i++) { // 开始向当前节点的四个方向(左右上下)遍历
                int nextx = curx + DIR[i][0];
                int nexty = cury + DIR[i][1]; // 获取周边四个方向的坐标

                // 坐标越界了,直接跳过
                if (nextx < 0 || nextx >= grid.length || nexty < 0 || nexty >= grid[0].length) {
                    continue;
                }

                if (!visited[nextx][nexty]) { // 如果节点没被访问过
                    queue.add(new int[]{nextx, nexty}); // 队列添加该节点为下一轮要遍历的节点
                    visited[nextx][nexty] = true; // 只要加入队列立刻标记,避免重复访问
                }
            }
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/910324.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenEuler 使用ffmpeg x11grab捕获屏幕流,rtsp推流,并用vlc播放

环境准备 安装x11grab(用于捕获屏幕流)和libx264(用于编码) # 基础开发环境&x11grab sudo dnf install -y \autoconf \automake \bzip2 \bzip2-devel \cmake \freetype-devel \gcc \gcc-c \git \libtool \make \mercurial \pkgconfig \zlib-devel \libX11-devel \libXext…

【Simulink仿真】混合储能平抑光伏功率波动

摘要 本文基于Simulink仿真平台&#xff0c;提出了一种混合储能系统&#xff08;Hybrid Energy Storage System, HESS&#xff09;来平抑光伏发电中的功率波动。该系统将超级电容与电池相结合&#xff0c;通过双向DC-DC变换器实现能量的动态分配。超级电容响应快&#xff0c;主…

C语言必做30道练习题

C语言练习30题&#xff08;分支循环&#xff0c;数组&#xff0c;函数&#xff0c;递归&#xff0c;操作符&#xff09; 目录 分支循环1.闰年的判断2.阅读代码&#xff0c;计算代码输出的结果3.输入一个1~7的数字&#xff0c;打印对应的星期几4.输入任意一个整数值&#xff0c;…

进程与线程+多线程优势

区别&#xff1a; 1、进程中包含线程&#xff0c;每一个进程都至少一个线程&#xff08;主线程&#xff09; 2、进程是申请系统资源的最小单位 3、进程是CPU调度的最小单位 4、线程之间共享进程申请的系统资源 5、一个线程崩溃了会影响整个进程 进程的组织方式&#xff1…

期权懂|期权策略中两边开卖方实值对冲会有盈利区间吗?

期权小懂每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 期权策略中两边开卖方实值对冲会有盈利区间吗&#xff1f; 一、期权策略中两边开卖方实值对冲的盈利区间可以‌核心策略‌分析‌&#xff1a; 期权对冲策略的核心是利用期权的特…

Follow软件的使用入门教程

开篇 看到很多兄弟还不知道怎么用这个当下爆火的浏览器&#xff01;在这里简单给需要入门的小伙伴一些建议&#xff1a; 介绍 简单解释一下&#xff0c;RSS 意思是简易信息聚合&#xff0c;用户可以通过 RSS 阅读器或聚合工具自主订阅并浏览各个平台的内容源&#xff0c;不用…

数字孪生的建构之路:从数据到智能

数字孪生是一种将物理实体系统或产品的数字化表示与其实体对应物相结合的概念&#xff0c;通过这种数字化技术&#xff0c;可以实时监测、预测和优化管理实体系统。实现数字孪生需要经历从数据采集、处理到智能化决策等多个步骤。以下是关于如何实现数字孪生的详细介绍。 1. 数…

【C#】创建一个主菜单和弹出菜单系统

文章目录 1. 创建WinForms项目2. 设计窗体3. 添加MenuStrip4. 配置菜单项5. 添加TextBox6. 编写事件处理代码7. 运行和测试 根据您提供的文件内容&#xff0c;看起来您需要在C# WinForms应用程序中设置一个窗体&#xff0c;其中包含一个文本框和几个菜单项&#xff0c;用于改变…

运维告警策略优化与实践

在运维行业中&#xff0c;告警策略的制定与执行是确保系统稳定性和业务连续性的关键环节。面对日益复杂的IT环境和不断变化的运维需求&#xff0c;如何合理制定并优化告警策略&#xff0c;成为运维团队必须面对的重要课题。本文将结合运维行业的现状、挑战及需求&#xff0c;深…

算法通关(3) -- kmp算法

KMP算法的原理 从题目引出 有两个字符串s1和s2,判断s1字符串是否包含s2字符串&#xff0c;如果包含返回s1包含s2的最左开头位置&#xff0c;不包含返回-1&#xff0c;如果是按照暴力的方法去匹配&#xff0c;以s1的每个字符作为开头&#xff0c;用s2的整体去匹配&#xff0c;…

vue3+vite搭建脚手架项目使用eletron打包成桌面应用+可以热更新

当前Node版本&#xff1a;18.12.0&#xff0c;npm版本&#xff1a;8.19.2 1.搭建脚手架项目 搭建Vue3ViteTs脚手架-CSDN博客 可删掉index.html文件的title标签 2.配置package.json {"name": "my-vite-project","private": true,"versi…

Java学习者的福音:SpringBoot教学辅助平台

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理教学辅助平台的相关信息成为必然。开发合适…

JAVA基础:数组 (习题笔记)

一&#xff0c;编码题 1&#xff0c;数组查找操作&#xff1a;定义一个长度为10 的一维字符串数组&#xff0c;在每一个元素存放一个单词&#xff1b;然后运行时从命令行输入一个单词&#xff0c;程序判断数组是否包含有这个单词&#xff0c;包含这个单词就打印出“Yes”&…

网络层5——IPV6

目录 一、IPv6 vs IPv4 1、对IPv6主要变化 2、IPv4 vs IPv6 二、IPv6基本首部 1、版本——4位 2、通信量类——8位 3、流标号——20位 4、有效载荷长度——16位 5、下一个首部——8位 6、跳数限制——8位 7、源 、 目的地址——128位 8、扩展首部 三、IPv6地址 1…

AIRIS 是一种学习型人工智能,它正在自学如何玩 Minecraft

AI开发公司SingularityNET和人工超级智能联盟&#xff08;ASI Alliance&#xff09;表示,随着人工智能学习如何通过操作玩游戏,一种新的学习型AI已被留在Minecraft的实例中。名为AIRIS&#xff08;自主智能增强推断象征主义&#xff09;的AI基本上是从Minecraft内部开始学习如何…

嵌入式学习-网络高级-Day01

嵌入式学习-网络高级-Day01 【1】Modbus协议 起源 分类 优势 应用场景 【2】Modbus TCP 特点 组成 报文头&#xff1a;7个字节 寄存器&#xff08;存储数据&#xff09; 功能码 总结 练习 【3】工具安装 Modbus Slave、Poll安装 网络调试助手 wireshark 练习 【1】Modbus协议 起…

Java项目实战II基于Spring Boot的问卷调查系统的设计与实现(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导 一、前言 在当今信息爆炸的时代&#xff0c;问卷调查…

【c++语言程序设计】数组(对象数组)

数组是一种按照特定顺序排列的对象集合体&#xff0c;数组中的每个对象称为“元素”。数组的每个元素都用“数组名下标”的形式来表示&#xff0c;并且同一数组内的所有元素类型相同。数组可以由任何类型的数据构成&#xff08;除 void 外&#xff09;&#xff0c;且数组的概念…

5分钟跑起来:Java构建的AI人工智能智能问答系统_springboot_spring ai_LLM_人工智能_开源免费使用

Agenda&#xff1a; 1&#xff09;介绍一下AI支持下的智能问答系统有哪些主要模块 2&#xff09;一个可以跑起来的代码样例&#xff0c;说明怎么用Java构建这个AI智能问答系统 AI人工智能智能问答系统简介 智能问答系统是一种利用人工智能技术理解并回答用户提问的应用。该系…

如何基于pdf2image实现pdf批量转换为图片

最近为了将pdf报告解析成为文本和图片&#xff0c;需要将大量多页的pdf文件拆分下单独的一页一页的图像&#xff0c;以便后续进行OCR和图像处理&#xff0c;因此就需要实现将pdf2image&#xff0c;本文主要结合开源的pdf2image和poppler&#xff0c;实现了pdf转换为png格式图片…