#19304. 培养皿中的生存游戏
培养皿中的生存游戏
你好!非常高兴能继续为你设计题目。
看到你已经掌握了滑动窗口(CpG岛)、排序与环形处理(质粒切割)、标记法(信使RNA剪接)。
这一次,我们来一道涉及模拟(Simulation)和状态更新的题目。这道题的模型原型是计算机科学中著名的“一维元胞自动机”(Cellular Automaton),但我们将其包装在高中生物必修一《分子与细胞》中细胞的生命历程这一背景下。
题目难度定位 GESP 5级(CSP-J T2/T3),考察重点是多轮次的状态模拟以及辅助数组(Double Buffering)的使用。
题目:培养皿中的生存游戏 (The Game of Cellular Survival)
【背景知识讲解】
在高中生物必修一中,我们学习了细胞的增殖、分化、衰老和凋亡。细胞的生存环境对其命运有决定性影响。 生物学中有两个有趣的现象:
- 接触抑制(Contact Inhibition):正常细胞在培养皿中贴壁生长,当细胞相互接触汇合成片时,会停止分裂增殖。如果周围太拥挤,细胞甚至会死亡(凋亡)。
- 旁分泌信号(Paracrine Signaling):细胞往往需要接收邻近细胞分泌的生长因子才能存活。如果一个细胞完全孤立,没有邻居,它可能会因为缺乏信号而“孤独死”。
基于这两个原理,我们可以模拟一排细胞的生存演变过程。
【题目描述】
实验室在一条狭长的微流控通道(可以看作一维数组)中培养了一排细胞。
通道共有 个格子,编号 到 。每个格子在初始时刻要么有一个活细胞(记为 1),要么是空的(记为 0)。
细胞的生存状态每过 1 秒会同时更新一次。更新规则如下(基于上一秒的状态):
-
对于原本是“活细胞”的位置:
- 过于拥挤:如果它的左边和右边都有活细胞(邻居数量 ),它会因为接触抑制而死亡(变为
0)。 - 过于孤单:如果它的左边和右边都没有活细胞(邻居数量 ),它会因为缺乏生长因子而死亡(变为
0)。 - 环境适宜:如果它恰好只有 个邻居(左边或右边),它将继续存活(保持
1)。
- 过于拥挤:如果它的左边和右边都有活细胞(邻居数量 ),它会因为接触抑制而死亡(变为
-
对于原本是“空位”的位置:
- 繁殖:如果它的左边和右边都有活细胞(邻居数量 ),这两个邻居会共同作用,分裂出一个新细胞填充该空位(变为
1)。 - 否则,保持为空(保持
0)。
- 繁殖:如果它的左边和右边都有活细胞(邻居数量 ),这两个邻居会共同作用,分裂出一个新细胞填充该空位(变为
边界说明: 对于通道两端的格子(编号 和 ),它们只有一个邻居(分别对应编号 和 )。
- 为了简化计算,我们假设通道之外(下标 和 )永远是空位(
0)。
现在给出初始状态,请计算经过 秒后的细胞分布情况。
【输入格式】
第一行包含两个整数 和 ,表示通道长度和模拟时间。
第二行包含一个长度为 的字符串 ,仅由字符 '0' 和 '1' 组成,表示初始状态。
【输出格式】
输出一行长度为 的字符串,表示 秒后的状态。
【样例数据】
输入:
7 1
0101010
输出:
0010100
样例解释:
初始状态:0 1 0 1 0 1 0 (下标 1~7)
- 位置 2 (1): 左(0) 右(0) 孤单,死 0
- 位置 3 (0): 左(1) 右(1) 繁殖,生 1
- 位置 4 (1): 左(0) 右(0) 孤单,死 0
- 位置 5 (0): 左(1) 右(1) 繁殖,生 1
- 位置 6 (1): 左(0) 右(0) 孤单,死 0
- 其余位置维持 0。
1秒后结果:
0 0 1 0 1 0 0。
【数据范围】
- 。
- 。
- 对于 100% 的数据,字符串只包含 '0' 和 '1'。
一、 思路提示
-
同时更新的陷阱:
- 题目中强调了“每过 1 秒会同时更新”。
- 比如计算位置 的新状态时,需要查看位置 和 。
- 如果你直接在原数组上修改:
S[i] = 新状态,当你接着计算S[i+1]时,你用到的S[i]就是刚刚改过的新状态了,但这不符合“基于上一秒状态”的规则。 - 核心技巧:你需要两个数组(或两个字符串)。一个存“上一秒(旧)”,一个存“这一秒(新)”。计算完一整轮后,再把“新”的变成“旧”的,准备下一轮。这叫双缓冲(Double Buffering)。
-
边界处理:
- 题目说了,下标 的左边(下标 )和下标 的右边(下标 )视为
0。 - 最方便的做法是:开一个长度为 的数组,把 放在中间(下标 到 ),而下标 和 始终保持为
0。这样在循环1到N时,就不需要写特殊的if (i==1)或if (i==N)判断了,直接访问i-1和i+1即可。
- 题目说了,下标 的左边(下标 )和下标 的右边(下标 )视为
-
规则逻辑梳理:
- 让
cnt = S[i-1] + S[i+1](统计邻居数量,字符 '0'/'1' 要转为数字)。 - 如果
S[i] == '1':cnt == 2死 (0)cnt == 0死 (0)cnt == 1活 (1)
- 如果
S[i] == '0':cnt == 2生 (1)- 其他 空 (
0)
- 让
二、 预备知识点总结
- 模拟算法:根据题目描述的规则,一步步执行。
- 双缓冲思想 / 辅助数组:解决“旧值被新值覆盖”导致计算错误的问题。
- 哨兵节点(Sentinel):通过填充边界(padding)来简化边界条件的判断代码。
三、 启发式教学:草稿纸上的推理过程
教练:“我们来玩这个细胞游戏。假设现在是第 0 秒,状态是 0 1 1 0 0。”
学生:“好的。”
教练:“我们先算第 1 秒。记得,我们要用第 0 秒的样子来判断。”
- 位置 1 (0):左边没东西(视为0),右边是1。邻居数=1。我是空位,邻居不是2,所以我还是 0。
- 位置 2 (1):左边(0),右边(1)。邻居数=1。我是活的,只有1个邻居,所以我存活 (1)。
- 位置 3 (1):左边(1),右边(0)。邻居数=1。我是活的,只有1个邻居,所以我存活 (1)。
- 位置 4 (0):左边(1),右边(0)。邻居数=1。我是空位,邻居不是2,所以我还是 0。
- 位置 5 (0):...还是 0。
结果:0 1 1 0 0。
教练:“咦?好像没变?”
学生:“是的,看起来这个状态比较稳定。”
教练:“那我们换个刺激的:0 1 0 1 0(中间隔开)。”
- 位置 2 (1):左0右0 孤单 死 (0)。
- 位置 3 (0):左1右1 繁殖 生 (1)。
- 位置 4 (1):左0右0 孤单 死 (0)。
结果:
0 0 1 0 0。 教练:“看,细胞位置发生了移动!这就是‘自动机’的神奇之处。”
时间复杂度分析:
- 我们要模拟 轮。
- 每一轮要遍历 个格子。
- 总复杂度是 。
- 题目中 ,乘积是 (一百万)。计算机一秒可以算 次。所以完全没问题!
四、 读题关键词总结
- “同时更新” 必须用两个数组(current 和 next),不能原地修改。
- “基于上一秒的状态” 再次确认需要双缓冲。
- “边界视为 0” 暗示可以在数组两头多开两个空间,避免数组越界。
- 或 的算法是可以接受的。