小华和小为是很要好的朋友,他们约定周末一起吃饭。
通过手机交流,他们在地图上选择了多个聚餐地点(由于自然地形等原因,部分聚餐地点不可达),求小华和小为都能到达的聚餐地点有多少个?
第二行开始具体输入地图信息,地图信息包含:
0 为通畅的道路
1 为障碍物(且仅1为障碍物)
2 为小华或者小为,地图中必定有且仅有2个 (非障碍物)
3 为被选中的聚餐地点(非障碍物)
4 4
2 1 0 3
0 1 2 1
0 3 0 0
0 0 0 0
2
4 4
2 1 2 3
0 1 0 0
0 1 0 0
0 1 0 0
0
读取输入的 m(行数)和 n(列数)。
读取 m 行的网格数据,并存入 grid 矩阵。
定义规则:
0:可以通行的空地。
1:墙壁,不能通行。
2:起点(有两个)。
3:关键地点(需要统计的地点)。
广度优先搜索(BFS):
从起点开始,使用 BFS 搜索所有可达的位置。
过程中记录访问过的节点,防止重复访问。
当遇到 3 时,加入 accessible 集合。
寻找起点:
遍历网格,找到所有 2 位置的坐标,存入 starts 列表。
求交集:
计算从华的起点和卫的起点分别能到达的 3 的位置。
取两个集合的交集,得到两个都能到达的关键地点。
输出:
输出交集的大小,即两个都能到达的 3 位置的数量
from collections import deque
# 读取输入的行数 m 和列数 n
m, n = map(int, input().split())
# 读取 m 行的网格数据,存入 grid 矩阵
grid = [list(map(int, input().split())) for _ in range(m)]
def bfs(start):
"""
使用广度优先搜索(BFS)找到从起点可以到达的所有关键地点(值为3的格子)。
:param start: (x, y) 起点坐标
:return: 可达的关键地点集合(包含所有能到的值为3的坐标)
"""
queue = deque([start]) # BFS 队列,初始包含起点
visited = set([start]) # 记录访问过的点,防止重复搜索
offsets = [(-1, 0), (1, 0), (0, -1), (0, 1)] # 方向向量:上、下、左、右
accessible = set() # 记录可达的关键地点(值为3的位置)
while queue:
x, y = queue.popleft() # 取出队列的当前搜索点
# 如果当前位置是关键地点(值为3),加入集合
if grid[x][y] == 3:
accessible.add((x, y))
# 遍历四个方向
for dx, dy in offsets:
nx, ny = x + dx, y + dy # 计算新坐标
# 判断新坐标是否在范围内,且不为墙(值为1),并且未访问过
if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] != 1 and (nx, ny) not in visited:
visited.add((nx, ny)) # 标记为已访问
queue.append((nx, ny)) # 加入队列继续搜索
return accessible # 返回可达的关键地点集合
# 查找所有起点(值为2的坐标)
starts = [(i, j) for i in range(m) for j in range(n) if grid[i][j] == 2]
# 分别计算从两个起点出发能够到达的关键地点
reachable_hua = bfs(starts[0]) # 第一个起点
reachable_wei = bfs(starts[1]) # 第二个起点
# 计算两个集合的交集,即两人都能到达的关键地点
common_places = reachable_hua & reachable_wei
# 输出能够被两人都到达的关键地点的数量
print(len(common_places))
定义规则:
0 表示可以通行的空地。
1 表示墙壁,无法通过。
2 表示起点。
3 表示需要统计的关键地点。
找到起点:分别找到两个起点(假设输入中有两个标记为 2 的点)。
深度优先搜索(DFS):从每个起点开始,使用 DFS 标记所有能够到达的点,分别记录华和卫能到达的位置。
统计结果:遍历整个网格,对于每个标记为 3 的位置,如果华和卫都能到达,则计数加一。
输出:输出能够被两个人都到达的关键地点的数量
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 输入矩阵的行数 m 和列数 n
int m = sc.nextInt();
int n = sc.nextInt();
int[][] grid = new int[m][n];
// 输入矩阵元素
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
grid[i][j] = sc.nextInt();
}
}
// 计算华和卫能够到达的共同地点数
System.out.println(countCommonPlaces(grid));
}
public static int countCommonPlaces(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
// 记录华和卫是否到达过的地点
boolean[][] visitedByHua = new boolean[m][n];
boolean[][] visitedByWei = new boolean[m][n];
// 找到华的起点 (2 表示起点)
int[] huaStart = findStart(grid, 2);
dfs(grid, visitedByHua, huaStart[0], huaStart[1], m, n);
// 重新找卫的起点 (因为华的起点已经被清除了)
int[] weiStart = findStart(grid, 2);
dfs(grid, visitedByWei, weiStart[0], weiStart[1], m, n);
int count = 0;
// 统计华和卫均能到达的地点 (3 表示地点)
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 3 && visitedByHua[i][j] && visitedByWei[i][j]) {
count++;
}
}
}
return count;
}
// 找到第一个指定值的坐标
public static int[] findStart(int[][] grid, int target) {
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == target) {
grid[i][j] = 0; // 避免重复找到同一个起点
return new int[]{i, j};
}
}
}
return null;
}
// 深度优先搜索函数,标记所有能达的地点
public static void dfs(int[][] grid, boolean[][] visited, int row, int col, int m, int n) {
if (row < 0 || row >= m || col < 0 || col >= n || grid[row][col] == 1 || visited[row][col]) {
return; // 超出边界或遇到墙或已访问过的地点
}
visited[row][col] = true;
// 向上、向下、向左、向右递归调用
dfs(grid, visited, row - 1, col, m, n);
dfs(grid, visited, row + 1, col, m, n);
dfs(grid, visited, row, col - 1, m, n);
dfs(grid, visited, row, col + 1, m, n);
}
}
更新中
更新中
更新中
如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏