华为OD机试 - 战场索敌 - 深度优先搜索dfs算法(Java 2023 B卷 100分)

在这里插入图片描述

目录

    • 一、题目描述
    • 二、输入描述
    • 三、输出描述
    • 四、深度优先搜索dfs
    • 五、解题思路
    • 六、Java算法源码
    • 七、效果展示
      • 1、输入
      • 2、输出
      • 3、说明
      • 4、如果增加目标敌人数量K为5
      • 5、来,上强度

华为OD机试 2023B卷题库疯狂收录中,刷题点这里

一、题目描述

有一个大小是N*M的战场地图,被枪毙 ‘#’ 分隔成大小不同的区域,上下左右四个方向相邻的空地’.',属于同一个区域,只有空地上可能存在敌人 ‘E’ ,请求出地图上总共有多少区域里的敌人数小于K。

二、输入描述

第一行输入为N,M,K;

  • N表示地图的行数;
  • M表示地图的列数;
  • K表示目标敌人数量;

取值范围:

N <= 100 、 M <= 100

第二行开始为N * M大小的字符数组。

三、输出描述

敌人数小于K的区域数量。

四、深度优先搜索dfs

在我们遇到的一些问题当中,有些问题我们不能够确切的找出数学模型,即找不出一种直接求解的方法,解决这一类问题,我们一般采用搜索的方法解决。搜索就是用问题的所有可能去试探,按照一定的顺序、规则,不断去试探,直到找到问题的解,试完了也没有找到解,那就是无解,试探时一定要试探完所有的情况(实际上就是穷举);

对于问题的第一个状态,叫初始状态,要求的状态叫目标状态。
搜索就是把规则应用于实始状态,在其产生的状态中,直到得到一个目标状态为止。
产生新的状态的过程叫扩展(由一个状态,应用规则,产生新状态的过程)。

搜索的要点:

  1. 初始状态;
  2. 重复产生新状态;
  3. 检查新状态是否为目标,是结束,否转(2);

如果搜索是以接近起始状态的程序依次扩展状态的,叫宽度优先搜索。

如果扩展是首先扩展新产生的状态,则叫深度优先搜索。

深度优先搜索用一个数组存放产生的所有状态。

  1. 把初始状态放入数组中,设为当前状态;
  2. 扩展当前的状态,产生一个新的状态放入数组中,同时把新产生的状态设为当前状态;
  3. 判断当前状态是否和前面的重复,如果重复则回到上一个状态,产生它的另一状态;
  4. 判断当前状态是否为目标状态,如果是目标,则找到一个解答,结束算法;
  5. 如果数组为空,说明无解。

五、解题思路

  1. 第一行输入三个数,分别是:地图的行数N、地图的列数M、目标敌人数量K;
  2. 通过Java8 Steam分隔初始化N、M、K;
  3. 定义一个二维数组visitedMatrix,记录是否被访问过;
  4. 定义二维矩阵matrix,存储N * M大小的字符数组;
  5. 定义变量areaSum,存储敌人数小于K的区域数量;
  6. 利用深度优先搜索dfs算法,获取敌人数小于K的区域数量;
  7. 输出敌人数小于K的区域数量。

六、Java算法源码

package com.guor.od;

import java.util.Scanner;
import java.util.*;

public class OdTest {
    public static boolean[][] visitedMatrix;
    public static int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int[] arr = Arrays.stream(in.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
        // 地图的行数
        int N = arr[0];
        // 地图的列数
        int M = arr[1];
        // 目标敌人数量
        int K = arr[2];

        // 矩阵某值是否被访问过
        visitedMatrix = new boolean[N][M];

        // 定义二维矩阵,存储N * M大小的字符数组
        char[][] matrix = new char[N][];
        for (int i = 0; i < N; i++) {
            matrix[i] = in.nextLine().toCharArray();
        }

        // 敌人数小于K的区域数量
        int areaSum = 0;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (visitedMatrix[i][j] || matrix[i][j] == '#') {
                    continue;
                }
                // 利用深度优先搜索dfs算法,获取敌人数小于K的区域数量
                areaSum += dfs(i, j, matrix, N, M) < K ? 1 : 0;
            }
        }
        // 输出敌人数小于K的区域数量
        System.out.println(areaSum);
    }

    /**
     * 利用深度优先搜索dfs算法,获取敌人数小于K的区域数量
     *
     * @param i 地图的行数,由0开始的变量
     * @param j 地图的列数,由0开始的变量
     * @param matrix 二维矩阵,N * M大小的字符数组
     * @param N 矩阵的总行数
     * @param M 矩阵的总列数
     * @return
     */
    public static int dfs(int i, int j, char[][] matrix, int N, int M) {
        // 敌军数量
        int enemy_count = 0;

        // 访问过
        visitedMatrix[i][j] = true;

        // 存在敌人 ‘E’,敌军数量+1
        if (matrix[i][j] == 'E') {
            enemy_count += 1;
        }

        // 栈中保存敌军的位置列表
        LinkedList<int[]> stack = new LinkedList<>();
        stack.add(new int[]{i, j});

        while (stack.size() > 0) {
            int[] pos = stack.removeLast();
            int x = pos[0], y = pos[1];

            // 上下左右四个方向
            for (int k = 0; k < 4; k++) {
                int new_x = x + directions[k][0];
                int new_y = y + directions[k][1];

                if (new_x >= 0 && new_x < N && new_y >= 0 && new_y < M && !visitedMatrix[new_x][new_y] && matrix[new_x][new_y] != '#') {
                    // 访问过
                    visitedMatrix[new_x][new_y] = true;

                    // 存在敌人 ‘E’,敌军数量+1
                    if (matrix[new_x][new_y] == 'E') {
                        enemy_count += 1;
                    }

                    stack.add(new int[]{new_x, new_y});
                }
            }
        }
        // 敌人数小于K的区域数量
        return enemy_count;
    }
}

七、效果展示

1、输入

4 6 3
…#EE.
E.#E…
#E#.E.
#.#…

2、输出

1

3、说明

地图被墙壁分为两个区域,左边区域有2个敌人,右边区域有4个敌人,符合条件的区域数量是1。

在这里插入图片描述

4、如果增加目标敌人数量K为5

地图被墙壁分为两个区域,左边区域有2个敌人,右边区域有4个敌人,符合条件的区域数量是2。

在这里插入图片描述

5、来,上强度

6 8 4
…#EE.#E
E.#E…#.
#E#.E.#.
#.#…#E
#.#.E.#E
#.#…#.

我草,不至于吧,哪吒,这眼花缭乱的,你这是“战场索鬼”吧?

好吧,上截图。

在这里插入图片描述

  • 如上图所示,战场被枪毙 ‘#’ 分隔成大小不同的区域
    1. 第一个区域2个敌人;
    2. 第二个区域5个敌人;
    3. 第三个区域3个敌人。
  • 目标敌人数量是4;
  • 敌人数小于K的区域数量为2;

下一篇:华为OD机试真题 Java 实现【简易内存池】【2023 B卷 200分 考生抽中题】

本文收录于,华为OD机试(JAVA)真题(A卷+B卷)

刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。

在这里插入图片描述

你可能感兴趣的:(搬砖工逆袭Java架构师,华为od,算法,深度优先)