记一次读佬哥2020年蓝桥杯模拟赛长草代码


第八题 长草
题目
【问题描述】
小明有一块空地,他将这块空地划分为 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 肯定是换点,也就是佬哥用的队列。
在这里插入图片描述

小结一下,写的很烂而且很乱,本来想稍微自己看懂写写,无奈佬哥的代码太优秀了,,,

全篇也就ans那个class很疑惑,但跟踪后面的if函数,了解到做有草坐标标记,一切就都通了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ECHO::

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值