代码随想录算法训练营第四十八天 | 图 | 深度搜索 | 广度搜索

Day 48 总结

  • 自己实现中遇到哪些困难
  • 今日收获,记录一下自己的学习时间
    • 11:40 - 14:30

图论

深度收缩 & 广度搜索
并查集
最小生成树
拓扑排序
最短路径算法

图论基础

    • 二维空间里,多个点之间相互连接
  • 图的种类
    • 有向图
    • 无向图
    • 加权
  • 度 Degree
    • 连接某个节点的边的数量
    • 出度,入度
  • 连通性
    • 节点联通情况
    • 连通图
      • 任意两个节点存在一条路径
    • 强连通图
      • 任务两个节点可以相互到达
    • 连通分量
      • 独立的连通子图(无向图中的极大连通子图)
    • 强连通分量
      • 有向图中极大强连通子图称之为该图的强连通分量
  • 图的构造
    • 邻接表
      • 数组 + 链表
      • 适用于稀疏图, 空间利用率高
    • 邻接矩阵
      • 二维数组
      • 表达简单,检查连接的速度块,适合稠密图
  • 图的遍历方式
    • 深度优先 dfs
    • 广度优先 bfs

深度优先搜索

  • 基本理解
    • 搜索方向,路径撤销(回溯)
  • 代码框架
  void dfs(参数) {
      if (终止条件) {
          存放结果;
          return;
      }

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

98. 所有可达路径

题目连接:98. 所有可达路径

题目描述:

给定一个有 n 个节点的有向无环图,节点编号从 1 到 n。请编写一个函数,找出并返回所有从节点 1 到节点 n 的路径。每条路径应以节点编号的列表形式表示。

输入:

N个节点,M个边

s节点 与 t节点 是相连的

输出:

所有从1出发的路径 找出并返回所有从节点 1 到节点 n 的路径

实现思路:

用 N*N 的邻接表保存节点的连接信息,通过dfs收集所有路径。

使用visted变量记录当前访问过哪些节点,用于撤销操作 有向无环,不需要visted记录

使用for循环遍历邻接表中当前节点的行,搜索所有相邻节点

path变量保存临时搜索路径,result变量收集所有路径

代码实现:
java 复制代码
public class Main {
    public static List<Integer> path = new ArrayList<>();
    public static List<List<Integer>> result = new ArrayList<>();
    public static int[][] graph;

    public static void main (String[] args) {
        /* code */
        Scanner in = new Scanner(System.in);
        String[] firstLine = in.nextLine().split(" ");
        int N = Integer.valueOf(firstLine[0]);
        int M = Integer.valueOf(firstLine[1]);

        graph = new int[N+1][N+1];
        visited = new boolean[N+1];
        for (int i=0; i<M; i++) {
            String[] line = in.nextLine().split(" ");
            int row = Integer.valueOf(line[0]);
            int col = Integer.valueOf(line[1]);
            graph[row][col] = 1;
        }        
        
        path.add(1);
        dfs1(1, N);
       
        if (result.size() == 0) 
            System.out.println(-1);
        else {
            for (List<Integer> p : result) {
                for (int i=0; i<p.size()-1; i++)
                    System.out.print(p.get(i) + " ");
                System.out.println(p.get(p.size()-1));
            }            
        }

    }
    
    public static void dfs1 (int node, int N) {
        // 到达路径末尾,收集路径
        if (node == N) { // 找到从1到N的路径
            result.add(new ArrayList<>(path));
            return;
        }

        for (int i=1; i<=N; i++) {
            if (graph[node][i] == 0) continue;
            path.add(i);
            dfs1(i, N);
            path.remove(path.size()-1);
        }            
    }

}

99. 岛屿数量

题目连接:99. 岛屿数量

题目描述:

给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。

输入:

N行,M列的矩阵

矩阵的具体数字,1代表一个岛,0代表水。

输出:

输出一个整数,表示岛屿的数量。如果不存在岛屿,则输出 0。

实现思路:

使用一个visted矩阵,标记都有哪些岛屿是访问过的。

按序访问每一个未访问过的岛屿,以该岛屿为起始点,进行深度搜索, 本次dfs结束之后,孤岛数量+1

深度搜索:

确定四个方向,上,右,下,左

分别dfs这四个分支

代码实现:
java 复制代码
public class Main {

    public static void main (String[] args) {
        /* code */
        Scanner in = new Scanner(System.in);
        String[] firstLine = in.nextLine().split(" ");
        int N = Integer.valueOf(firstLine[0]);
        int M = Integer.valueOf(firstLine[1]);
        int[][] graph = new int[N][M];
        boolean[][] visited = new boolean[N][M];
        for (int i=0; i<N; i++) {
            for (int j=0; j<M; j++) {
                graph[i][j] = in.nextInt();   
            }
        }        
        
        // for (int i=0; i<N; i++) {
        //     System.out.println(Arrays.toString(graph[i]));
        // }
        int ct = 0;
        for (int i=0; i<N; i++) {
            for (int j=0; j<M; j++) {
                if (graph[i][j] == 1 && !visited[i][j]) {
                    // System.out.println("start:" + i + " " + j);
                    dfs(graph, visited,i,j, N, M);
                    ct++;
                }
            }
        }

        System.out.println(ct);
    }

    public static void dfs(int[][] graph, boolean[][] visited, int x, int y, int N, int M) {
        int[] directions = {-1,0, 0,1, 1,0, 0,-1}; // 上右下左
        visited[x][y] = true;

        for (int i=0; i<4; i++) {
            int directX = directions[i*2];
            int directY = directions[i*2+1];

            if (directX+x >= 0 && directX+x < N && directY+y >= 0 && directY+y < M &&
                graph[directX+x][directY+y]==1 && !visited[directX+x][directY+y]) {
                // System.out.println("dfs:" + (directX+x) + " " + (directY+y));
                dfs(graph, visited, directX+x, directY+y, N, M);
            }
        }
    }
    

}

广度优先搜索

  • BFS, 求点与点之间最短路径,以起始点为圆心,按圈搜索

  • 搜索过程

    • 起始点,起始点的四个方向
    • 队列保存顺(逆)时针的邻居
    java 复制代码
    int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 表示四个方向
    // grid 是地图,也就是一个二维数组
    // visited标记访问过的节点,不要重复访问
    // x,y 表示开始搜索节点的下标
    void bfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int x, int y) {
        queue<pair<int, int>> que; // 定义队列
        que.push({x, y}); // 起始节点加入队列
        visited[x][y] = true; // 只要加入队列,立刻标记为访问过的节点
        while(!que.empty()) { // 开始遍历队列里的元素
            pair<int ,int> cur = que.front(); que.pop(); // 从队列取元素
            int curx = cur.first;
            int cury = cur.second; // 当前节点坐标
            for (int i = 0; i < 4; i++) { // 开始想当前节点的四个方向左右上下去遍历
                int nextx = curx + dir[i][0];
                int nexty = cury + dir[i][1]; // 获取周边四个方向的坐标
                if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue;  // 坐标越界了,直接跳过
                if (!visited[nextx][nexty]) { // 如果节点没被访问过
                    que.push({nextx, nexty});  // 队列添加该节点为下一轮要遍历的节点
                    visited[nextx][nexty] = true; // 只要加入队列立刻标记,避免重复访问
                }
            }
        }
    
    }
99. 岛屿数量

题目连接:99. 岛屿数量

题目描述:

给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。

输入:

N行,M列的矩阵

矩阵的具体数字,1代表一个岛,0代表水。

输出:

输出一个整数,表示岛屿的数量。如果不存在岛屿,则输出 0。

实现思路:

使用一个visted矩阵,标记都有哪些岛屿是访问过的。

按序访问每一个未访问过的岛屿,以该岛屿为起始点,进行广度搜索, 本次bfs结束之后,孤岛数量+1

广度搜索:

确定四个方向,上,右,下,左

使用一个队列将这个四个岛屿存储起来,然后bfs

代码实现:
java 复制代码
public class Main {
    public static void main (String[] args) {
        /* code */
        Scanner in = new Scanner(System.in);
        String[] firstLine = in.nextLine().split(" ");
        int N = Integer.valueOf(firstLine[0]);
        int M = Integer.valueOf(firstLine[1]);
        int[][] graph = new int[N][M];
        boolean[][] visited = new boolean[N][M];
        for (int i=0; i<N; i++) {
            for (int j=0; j<M; j++) {
                graph[i][j] = in.nextInt();   
            }
        }        
        

        int ct = 0;
        for (int i=0; i<N; i++) {
            for (int j=0; j<M; j++) {
                if (graph[i][j] == 1 && !visited[i][j]) {
                    // System.out.println("start:" + i + " " + j);
                    bfs(graph, visited,i,j, N, M);
                    ct++;
                }
            }
        }
        System.out.println(ct);
    }

    public static void bfs(int[][] graph, boolean[][] visited, int X, int Y, int N, int M) {
        int[] directions = {-1,0, 0,1, 1,0, 0,-1}; // 上右下左
        Deque<int[]> queue = new LinkedList<>();

        queue.add(new int[]{X, Y});
        visited[X][Y] = true;

        while (!queue.isEmpty()) {
            int[] land = queue.poll();
            int x = land[0];
            int y = land[1];
            
            for (int i=0; i<4; i++) {
                int directX = directions[i*2];
                int directY = directions[i*2+1];

                if (directX+x >= 0 && directX+x < N && directY+y >= 0 && directY+y < M &&
                    graph[directX+x][directY+y]==1 && !visited[directX+x][directY+y]) {

                    queue.add(new int[]{directX+x,directY+y});
                    visited[directX+x][directY+y] = true;
                }
            }

        }

    }
    

}
相关推荐
m0_663234011 小时前
Rust并发编程实践:10分钟入门系统级编程
python·算法·rust
zdsji1 小时前
如何制作安装包打包软件
算法·rust·vue
糖葫芦君2 小时前
TD时间差分算法
人工智能·算法
没明白白5 小时前
插入排序:一种简单而直观的排序算法
java·算法·排序算法
程序员南飞5 小时前
算法-数据结构-图的构建(邻接矩阵表示)
java·数据结构·算法·职场和发展
指掀涛澜天下惊5 小时前
DirectX12(D3D12)基础教程三 线性代数与3D世界空间
线性代数·算法·机器学习·3d
程序趣谈6 小时前
算法随笔_57 : 游戏中弱角色的数量
数据结构·python·算法
滨HI06 小时前
P8772 [蓝桥杯 2022 省 A] 求和--简单题的陷阱——(不开long long见祖宗!!!
数据结构·c++·算法·职场和发展·蓝桥杯
楼台的春风6 小时前
图像金字塔
图像处理·人工智能·opencv·算法·计算机视觉·matlab·嵌入式
IT猿手7 小时前
2025最新高维多目标优化:基于城市场景下无人机三维路径规划的导航变量的多目标粒子群优化算法(NMOPSO),MATLAB代码
android·开发语言·算法·机器学习·matlab·无人机