1. 问题描述:
有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻(上下左右四个方向)的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的瓷砖。
输入格式
输入包括多个数据集合。每个数据集合的第一行是两个整数 W 和 H,分别表示 x 方向和 y 方向瓷砖的数量。在接下来的 H 行中,每行包括 W 个字符。每个字符表示一块瓷砖的颜色,规则如下
1)'.':黑色的瓷砖;
2)'#':红色的瓷砖;
3)'@':黑色的瓷砖,并且你站在这块瓷砖上。该字符在每个数据集合中唯一出现一次。
当在一行中读入的是两个零时,表示输入结束。
输出格式
对每个数据集合,分别输出一行,显示你从初始位置出发能到达的瓷砖数(记数时包括初始位置的瓷砖)。
数据范围
1 ≤ W,H ≤ 20
输入样例:
6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
0 0
输出样例:
45
来源:https://www.acwing.com/problem/content/description/1115/
2. 思路分析:
分析题目可以知道这是一道连通性检测的题目,可以使用dfs或者bfs来解决,因为数据规模不是特别大所以可以使用dfs来解决,连通性检测的搜索问题一般是在一个棋盘内搜索,所以不需要回溯,也即起点的状态不会影响到下一次的搜索,所以一般不需要回溯的,如果是另外一类将棋盘看成是一种状态那么是需要进行回溯的,因为当递归退回到当前这一层的时候当前整个棋盘的状态已经改变了所以需要恢复现场,需要保证从当前状态往下搜索的时候的状态是一致的那么就需要进行回溯。
3. 代码如下:
from typing import List
class Solution:
def dfs(self, n: int, m: int, x: int, y: int, st: List[List[int]], g: List[str], pos: List[List[int]]):
count = 1
st[x][y] = 1
for i in range(4):
a, b = x + pos[i][0], y + pos[i][1]
# 越界了跳过
if a < 0 or a >= n or b < 0 or b >= m: continue
# 已经访问过了条过
if st[a][b] == 1: continue
# 不是黑砖直接跳过
if g[a][b] != ".": continue
# 当前这个往下递归可以搜索到的黑砖
count += self.dfs(n, m, a, b, st, g, pos)
return count
def process(self):
while True:
# 注意输入的是列数和行数
m, n = map(int, input().split())
# 输入m = n = 0的时候break
if m == 0 and n == 0: break
g = list()
for i in range(n):
g.append(input())
st = [[0] * (m + 10) for i in range(n + 10)]
pos = [[0, 1], [0, -1], [1, 0], [-1, 0]]
# 找到起点的位置
x = y = 0
for i in range(n):
for j in range(m):
# "@"的位置就是起点的位置
if g[i][j] == "@":
x, y = i, j
break
print(self.dfs(n, m, x, y, st, g, pos))
if __name__ == '__main__':
Solution().process()