第八题 长草
题目
【问题描述】
小明有一块空地,他将这块空地划分为 n 行 m 列的小块,每行和每列的长度都为 1。
小明选了其中的一些小块空地,种上了草,其他小块仍然保持是空地。
这些草长得很快,每个月,草都会向外长出一些,如果一个小块种了草,则它将向自己的上、下、左、右四小块空地扩展,这四小块空地都将变为有草的小块。
请告诉小明,k 个月后空地上哪些地方有草。
【输入格式】
输入的第一行包含两个整数 n, m。
接下来 n 行,每行包含 m 个字母,表示初始的空地状态,字母之间没有空格。如果为小数点,表示为空地,如果字母为 g,表示种了草。
接下来包含一个整数 k。
【输出格式】
输出 n 行,每行包含 m 个字母,表示 k 个月后空地的状态。如果为小数点,表示为空地,如果字母为 g,表示长了草。
【样例输入】
4 5
.g…
…
…g…
…
2
【样例输出】
gggg.
gggg.
ggggg
.ggg.
【评测用例规模与约定】
对于 30% 的评测用例,2 <= n, m <= 20。
对于 70% 的评测用例,2 <= n, m <= 100。
对于所有评测用例,2 <= n, m <= 1000,1 <= k <= 1000。
一天心血来潮,看看大佬的写法,想着能从佬哥那里学到点精髓,下面是大佬的代码
class Block:
i = 0
j = 0
month = 0
def __init__(self, i, j, month):
self.i = i
self.j = j
self.month = month
dx = (-1, 1, 0, 0)
dy = (0, 0, -1, 1)
if __name__ == '__main__':
(N, M) = (int(x) for x in input().strip().split(' '))
data = [input() for _ in range(0, N)] # 记录原始数据
ans = [['.'] * M for _ in range(N)] # 记录答案 # 全部初始化为.
K = int(input().strip()) # 输入K
q = [Block(i, j, 0) for i in range(N) for j in range(M) if data[i][j] == 'g'] # bfs的原始队列
# 模拟队列起始位置
qBegin = 0
# 队列操作
while qBegin < len(q):
x, y, month = q[qBegin].i, q[qBegin].j, q[qBegin].month
qBegin += 1
ans[x][y] = 'g' # 标记在结果中
if month < K:
for (nx, ny) in [(x + _x, y + _y) for (_x, _y) in zip(dx, dy)]:
if 0 <= nx < N and 0 <= ny < M and ans[nx][ny] == '.':
q.append(Block(nx, ny, month + 1))
ans[nx][ny] = 'g'
# 输出
for i in range(N):
print(''.join(ans[i]))
无奈,实在是菜,看了有序的bfs算法后也没看到佬哥再写啥。。
隔了一天后,打算放弃,后来想想也是一道题,看看也不妨。。
data = [input() for _ in range(0, N)] # 记录原始数据
ans = [['.'] * M for _ in range(N)] # 记录答案 # 全部初始化为.
佬哥这里定义了两个变量存储,ans猜测按有序bfs肯定最后要做替换的。
q = [Block(i, j, 0) for i in range(N) for j in range(M) if data[i][j] == 'g'] # bfs的原始队列
然后这行,没看懂q的含义,(菜的扣脚),一时陷入了僵局,,看佬哥的注释意思是做个原始队列。 但我没做过队列的算法,并不清楚,后面顿悟了,
劳资看不懂你写的啥,if函数还能骗人不成?? 看到if这里对坐标[i][j]做标记,也就是g,长草的地方。这个问题解决了后面也是同样的思路:
x, y, month = q[qBegin].i, q[qBegin].j, q[qBegin].month
qBegin += 1
ans[x][y] = 'g' # 标记在结果中
这里三行就是获取标记有草(也就是g)的坐标。 查资料,这个队列问题和之前一直在做的递归问题很像。
然后最重要的地方在这里: 直接看佬哥写的if函数,这里的nx和ny就是草地的坐标后面加了==’.’,这样快速筛选含有没草的地,前面的嵌套就是做一个遍历,类似我下面做的图
for (nx, ny) in [(x + _x, y + _y) for (_x, _y) in zip(dx, dy)]:
if 0 <= nx < N and 0 <= ny < M and ans[nx][ny] == '.':
q.append(Block(nx, ny, month + 1))
ans[nx][ny] = 'g'
这里直接看运行的结果,第一次i=8 ,第二次i=7而刚好y=1,说明i=x-y,是先遍历后面的值。所以上面佬哥那个遍历的肯定是存在 某个点(1,1)然后(1-1,1)然后在接着遍历(1+1,1),(1,1-1),(1,1+1),这种形式的遍历
那前面那个 qBegin = 0;qBegin += 1
肯定是换点,也就是佬哥用的队列。
小结一下,写的很烂而且很乱,本来想稍微自己看懂写写,无奈佬哥的代码太优秀了,,,