2025寒假算法练习——Week 8

文章目录

前段时间做的搜索练习题

习题均来自 NEFU OJ

Problem 784 | 白与黑-搜索

  • Description

有一间长方形的房子,地上铺了白色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。

  • Input

包括多个数据集合。每个数据集合的第一行是两个整数W 和H,分别表示x 方向
和y 方向瓷砖的数量。W 和H 都不超过20。在接下来的H 行中,每行包括W 个字符。
每个字符表示一块瓷砖的颜色,规则如下:
1)‘.’:黑色的瓷砖;
2)‘#’:白色的瓷砖;
3)‘@’:黑色的瓷砖,并且你站在这块瓷砖上。该字符在每个数据集合中唯一出现一次。
当在一行中读入的是两个零时,表示输入结束。

  • Output

对每个数据集合,分别输出一行,显示你从初始位置出发能到达的瓷砖数(记数时包括初始位置的瓷砖)。

  • Sample Input
 16 9
 2....#.
 3.....#
 4......
 5......
 6......
 7......
 8......
 9#@...#
10.#..#.
110 0
  • Sample Output
145

广搜找连通块。

 1import java.util.Scanner;
 2import java.util.Queue;
 3import java.util.LinkedList;
 4
 5public class Main {
 6    public static void main(String[] args) {
 7        int[] directions = { 1, 0, -1, 0, 0, 1, 0, -1 };
 8        try (Scanner sc = new Scanner(System.in)) {
 9            while (true) {
10                int col = sc.nextInt(), row = sc.nextInt();
11                if (col == 0 && row == 0) {
12                    break;
13                }
14                sc.nextLine();
15                Boolean[][] tiles = new Boolean[row][col];
16                int x = 0, y = 0;
17                for (int i = 0; i < row; i++) {
18                    String line = sc.nextLine();
19                    for (int j = 0; j < col; j++) {
20                        tiles[i][j] = line.charAt(j) == '#' ? false : true;
21                        if (line.charAt(j) == '@') {
22                            x = i;
23                            y = j;
24                        }
25                    }
26                }
27
28                Queue<int[]> queue = new LinkedList<>();
29                int count = 0;
30                queue.add(new int[] { x, y });
31                tiles[x][y] = false;
32                while (!queue.isEmpty()) {
33                    int[] curr = queue.poll();
34                    count++;
35                    for (int i = 0; i < 8; i += 2) {
36                        int nx = curr[0] + directions[i], ny = curr[1] + directions[i + 1];
37                        if (nx >= 0 && nx < row && ny >= 0 && ny < col && tiles[nx][ny]) {
38                            queue.offer(new int[] { nx, ny });
39                            tiles[nx][ny] = false;
40                        }
41                    }
42                }
43                System.out.println(count);
44            }
45        }
46    }
47}

Problem 558 | 迷宫寻路-搜索

  • Description

AC小公主很喜欢设计迷宫,她设计的迷宫只有两个口,一个入口,一个出口。但小公主有时候很调皮,她会让挑战者走不出迷宫。现在给你AC小公主的迷宫请你判断挑战者能否成功从出口走出迷宫,迷宫包证边界为障碍物,只有两个不同的入口。
“#”代表障碍物,“*”代表可走的路。

  • Input

输入有多组,每组输入两个正整数n,m( 2 < n < m < 1000)。
接下来n行,每行有m个字符。

  • Output

每组测试实例,若挑战者能走出迷宫输出”YES”,否则输出“NO”。

  • Sample Input
13 3
2#*#
3#*#
4#*#
53 3
6#*#
7###
8#*#
  • Sample Output
1YES
2NO

这道题用深搜和广搜都能解。

广搜写法:

 1import java.util.Scanner;
 2import java.util.Queue;
 3import java.util.LinkedList;
 4
 5public class Main {
 6    public static void main(String[] args) {
 7        int[] directions = { 1, 0, -1, 0, 0, 1, 0, -1 };
 8        try (Scanner sc = new Scanner(System.in)) {
 9            while (sc.hasNext()) {
10                int row = sc.nextInt(), col = sc.nextInt();
11                Boolean[][] maze = new Boolean[row][col];
12                String line;
13                int x = 0, y = 0;
14                for (int i = 0; i < row; i++) {
15                    line = sc.next();
16                    for (int j = 0; j < col; j++) {
17                        maze[i][j] = line.charAt(j) == '*';
18                        if ((i == 0 || i == row - 1 || j == 0 || j == col - 1) && maze[i][j]) {
19                            x = i;
20                            y = j;
21                        }
22                    }
23                }
24
25                boolean found = false;
26                Queue<int[]> queue = new LinkedList<>();
27                queue.add(new int[] { x, y });
28                maze[x][y] = false;
29                while (!queue.isEmpty()) {
30                    int[] curr = queue.poll();
31                    if ((curr[0] == 0 || curr[0] == row - 1 || curr[1] == 0 || curr[1] == col - 1)
32                            && !(curr[0] == x && curr[1] == y)) {
33                        System.out.println("YES");
34                        found = true;
35                        break;
36                    }
37                    for (int i = 0; i < 8; i += 2) {
38                        int nx = curr[0] + directions[i], ny = curr[1] + directions[i + 1];
39                        if (nx >= 0 && nx < row && ny >= 0 && ny < col && maze[nx][ny]) {
40                            maze[nx][ny] = false;
41                            queue.add(new int[] { nx, ny });
42                        }
43                    }
44                }
45                if (!found) {
46                    System.out.println("NO");
47                }
48            }
49        }
50    }
51}

深搜写法:

 1import java.util.Scanner;
 2
 3public class Main {
 4
 5    public static int[] directions = { 1, 0, -1, 0, 0, 1, 0, -1 };
 6
 7    public static void main(String[] args) {
 8        try (Scanner sc = new Scanner(System.in)) {
 9            while (sc.hasNext()) {
10                int row = sc.nextInt(), col = sc.nextInt();
11                Boolean[][] maze = new Boolean[row][col];
12                String line;
13                int beginX = 0, beginY = 0, endX = 0, endY = 0;
14                for (int i = 0; i < row; i++) {
15                    line = sc.next();
16                    for (int j = 0; j < col; j++) {
17                        maze[i][j] = line.charAt(j) == '*';
18                        if ((i == 0 || i == row - 1 || j == 0 || j == col - 1) && maze[i][j]) {
19                            if (beginX == 0 && beginY == 0) {
20                                beginX = i;
21                                beginY = j;
22                            } else {
23                                endX = i;
24                                endY = j;
25                            }
26                        }
27                    }
28                }
29
30                if (dfs(maze, beginX, beginY, endX, endY, row, col)) {
31                    System.out.println("YES");
32                } else {
33                    System.out.println("NO");
34                }
35            }
36        }
37    }
38
39    public static boolean dfs(Boolean[][] maze, int x, int y, int endX, int endY, int row, int col) {
40        maze[x][y] = false;
41        if (x == endX && y == endY) {
42            return true;
43        }
44
45        boolean result = false;
46        for (int i = 0; i < 8; i += 2) {
47            int nextX = x + directions[i];
48            int nextY = y + directions[i + 1];
49            if (nextX >= 0 && nextX < row && nextY >= 0 && nextY < col && maze[nextX][nextY]) {
50                result = dfs(maze, nextX, nextY, endX, endY, row, col) || result;
51            }
52        }
53
54        return result;
55    }
56}

maze 数组既可以用来记录路径,又可以当作 visited 用。

Problem 1696 | 猴群-搜索

  • Description

给你一个数字矩阵,其中数字由0-9构成,0代表树木,1-9代表猴子;凡是有0和边缘围起来的区域是猴群。请你计算猴群的数目?

  • Input

第1行为n和 m,代表行和列数,(1<=n,m<=100)

  • Output

输出猴群的数目!

  • Sample Input
14 10
20234500067
31034560500
42045600671
50000000089
  • Sample Output
14
 1import java.util.Scanner;
 2import java.util.Queue;
 3import java.util.LinkedList;
 4
 5public class Main {
 6
 7    public static void main(String[] args) {
 8        int[] directioins = { 1, 0, -1, 0, 0, 1, 0, -1 };
 9        try (Scanner sc = new Scanner(System.in)) {
10            int row = sc.nextInt(), col = sc.nextInt();
11            sc.nextLine();
12            int[][] forest = new int[row][col];
13            String line;
14            for (int i = 0; i < row; i++) {
15                line = sc.nextLine();
16                for (int j = 0; j < col; j++) {
17                    forest[i][j] = line.charAt(j) == '0' ? 0 : 1;
18                }
19            }
20
21            int count = 0;
22            for (int i = 0; i < row; i++) {
23                for (int j = 0; j < col; j++) {
24                    if (forest[i][j] != 0) {
25                        Queue<int[]> queue = new LinkedList<>();
26                        queue.add(new int[] { i, j });
27                        forest[i][j] = 0;
28                        while (!queue.isEmpty()) {
29                            int[] curr = queue.poll();
30                            for (int k = 0; k < 8; k += 2) {
31                                int x = curr[0] + directioins[k], y = curr[1] + directioins[k + 1];
32                                if (x >= 0 && x < row && y >= 0 && y < col && forest[x][y] != 0) {
33                                    queue.add(new int[] { x, y });
34                                    forest[x][y] = 0;
35                                }
36                            }
37                        }
38                        count++;
39                    }
40                }
41            }
42
43            System.out.println(count);
44        }
45    }
46}

Problem 1702 | 01迷宫-搜索

  • Description

有一个仅由数字0与1组成的n×n格迷宫。若你位于一格0上,那么你可以移动到相邻4格中的某一格1上,同样若你位于一格1上,那么你可以移动到相邻4格中的某一格0上。
你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身)。

  • Input

第1行为两个正整数n,m.
下面n行,每行n个字符,字符只可能是0或者1,字符之间没有空格。
接下来m行,每行2个用空格分隔的正整数i,j,对应了迷宫中第i行第j列的一个格子,询问从这一格开始能移动到多少格。

  • Output

m行,对于每个询问输出相应答案。

  • Sample Input
12 2
201
310
41 1
52 2
  • Sample Output
14
24
  • Hint

n<=1000,m<=100000

  • Source

洛谷 2020.1.27,数据已更新,原题解可能超时

又是一个找连通块问题。为了避免超时,首先要用 C++ 做(Java 确实会超时),其次不要一上来就把所有连通块都搜索一遍。每次查询时先看看这一个连通块之前是不是处理过,如果处理过就直接输出,否则再搜索,而且每次搜索完都将结果存起来。

 1#define _CRT_SECURE_NO_WARNINGS
 2
 3#include <cstdio>
 4#include <queue>
 5
 6using namespace std;
 7
 8int directions[8] = { 1, 0, -1, 0, 0, 1, 0, -1 };
 9char line[1005];
10bool maze[1005][1005];
11bool visited[1005][1005] = { false };
12int memo[1005][1005] = { 0 };
13
14void bfs(int x, int y, int n) {
15    queue<pair<int, int>> cache;
16    queue<pair<int, int>> q;
17    int count = 0;
18    q.push(make_pair(x, y));
19    visited[x][y] = true;
20    while (!q.empty()) {
21        int cx = q.front().first;
22        int cy = q.front().second;
23        count++;
24        cache.push(q.front());
25        q.pop();
26
27        for (int i = 0; i < 8; i += 2) {
28            int nx = cx + directions[i];
29            int ny = cy + directions[i + 1];
30            if (nx >= 0 && nx < n && ny >= 0 && ny < n && !visited[nx][ny] && maze[nx][ny] ^ maze[cx][cy]) {
31                q.push(make_pair(nx, ny));
32                visited[nx][ny] = true;
33            }
34        }
35    }
36
37    while (!cache.empty()) {
38        int cx = cache.front().first;
39        int cy = cache.front().second;
40        memo[cx][cy] = count;
41        cache.pop();
42    }
43}
44
45int main() {
46    int n, m;
47    scanf("%d %d", &n, &m);
48    for (int i = 0; i < n; i++) {
49        scanf("%s", &line);
50        for (int j = 0; j < n; j++) {
51            maze[i][j] = line[j] == '1';
52        }
53    }
54
55    for (int i = 0; i < m; i++) {
56        int x, y;
57        scanf("%d %d", &x, &y);
58        x--;
59        y--;
60        if (visited[x][y]) {
61            printf("%d\n", memo[x][y]);
62            continue;
63        }
64        else {
65            bfs(x, y, n);
66            printf("%d\n", memo[x][y]);
67        }
68    }
69}

相关系列文章