#lydlx05x0E25. 玉米田 Corn Fields
玉米田 Corn Fields
题目描述
农夫约翰的土地由 个小方格组成,现在他要在土地里种植玉米。
非常遗憾,部分土地是不育的,无法种植。
而且,相邻的土地不能同时种植玉米,也就是说种植玉米的所有方格之间都不会有公共边缘。
现在给定土地的大小,请你求出共有多少种种植方法。
土地上什么都不种也算一种方法。
输入格式
第 1 行包含两个整数 和 。
第 2..M+1 行:每行包含 个整数 0 或 1,用来描述整个土地的状况,1 表示该块土地肥沃,0 表示该块土地不育。
输出格式
输出总种植方法对 取模后的值。
样例
2 3
1 1 1
0 1 0
9
样例解释
土地状况
土地:
1 1 1
0 1 0
1 表示肥沃,0 表示不育(不能种植)。
种植规则
- 只能在肥沃的土地上种植。
- 相邻(有公共边)的土地不能同时种植。
计算种植方案数
我们枚举所有可能的种植方案。
将土地格子编号(从左到右,从上到下): (1,1)=1, (1,2)=1, (1,3)=1 (2,1)=0, (2,2)=1, (2,3)=0
只有肥沃的格子才能种,所以可种植的格子: (1,1), (1,2), (1,3), (2,2)。
我们需要选择这些格子的一个子集,使得没有两个选中的格子相邻。
枚举方案
用二进制表示每行的种植状态(1 表示种,0 表示不种),注意只能种在肥沃格子上。
第一行:三个格子都肥沃,可能的状态(3位二进制): 000, 001, 010, 011, 100, 101, 110, 111。 但需要满足相邻不能同时种:即二进制中不能有相邻的 1。
- 000: 有效
- 001: 有效(只有最后一个种)
- 010: 有效
- 011: 无效(后两位相邻)
- 100: 有效
- 101: 有效(第一位和第三位种,中间不种,不相邻)
- 110: 无效(前两位相邻)
- 111: 无效
所以第一行有效状态:000, 001, 010, 100, 101。
第二行:只有中间格子 (2,2) 肥沃,其他不育。 所以种植状态只能是 0 或 1(只有一列?第二行有3列,但只有第二列肥沃,所以状态只有两种:000 和 010?注意状态要对应整行,不育的格子不能种,所以状态中对应不育格子的位必须是 0。因此第二行的可能状态:000 和 010(因为只有第二列可以种,第一列和第三列必须为 0)。 同时,状态自身不能有相邻的 1(但这里只有一个 1,所以都满足)。
行间相邻检查
相邻行同一列的格子不能同时种。
我们枚举所有组合: 第一行状态有 5 种,第二行状态有 2 种,共 10 种组合,检查行间相邻:
设第一行状态 s1,第二行状态 s2,需要满足 (s1 & s2) == 0(同一列不能同时为 1)。
列举:
- s1=000 (0), s2=000 (0) → 0 & 0 = 0,有效。
- s1=000 (0), s2=010 (2) → 0 & 2 = 0,有效。
- s1=001 (1), s2=000 → 1 & 0 = 0,有效。
- s1=001 (1), s2=010 (2) → 1 & 2 = 0,有效。
- s1=010 (2), s2=000 → 2 & 0 = 0,有效。
- s1=010 (2), s2=010 (2) → 2 & 2 = 2 ≠ 0,无效。
- s1=100 (4), s2=000 → 4 & 0 = 0,有效。
- s1=100 (4), s2=010 (2) → 4 & 2 = 0,有效。
- s1=101 (5), s2=000 → 5 & 0 = 0,有效。
- s1=101 (5), s2=010 (2) → 5 & 2 = 0,有效。
无效的只有第 6 种,所以有效组合 9 种。
对应种植方案:
- 都不种。
- 只种 (2,2)。
- 只种 (1,3)。
- 种 (1,3) 和 (2,2)(不相邻,因为 (1,3) 和 (2,2) 斜对角,不算相邻,只有上下左右相邻才禁止。这里 (1,3) 和 (2,3) 相邻,但 (2,3) 不育,所以没问题)。
- 只种 (1,2)。
- 无效。
- 只种 (1,1)。
- 种 (1,1) 和 (2,2)(不相邻)。
- 种 (1,1) 和 (1,3)。
- 种 (1,1), (1,3), (2,2)(检查相邻:(1,1) 和 (1,3) 不相邻,(1,3) 和 (2,2) 斜对角不相邻,(1,1) 和 (2,2) 斜对角不相邻,所以有效)。
所以总共 9 种方案,输出 9。
数据范围
算法分析
这是一个典型的状态压缩动态规划问题,类似“玉米田”或“炮兵阵地”问题。
状态表示
由于 ,我们可以用二进制数表示一行的种植状态(1 表示种,0 表示不种)。
设 表示前 行,且第 行的种植状态为 时的总方案数。
状态转移
,其中 是第 行的状态,满足:
- 是合法的:即 中不能有相邻的 1(因为同一行相邻格子不能种)。
- 只能种在肥沃的土地上:即对于第 行的土地状况 (也是一个二进制数,肥沃为 1,不育为 0),必须满足 (即 中为 1 的位在 中也必须为 1)。
- 和 不能有同一列为 1:即 。
初始化
(第 0 行没有土地,状态只能为 0)。
最终答案
所有 的和,对 取模。
优化
- 预处理所有合法的行状态(即没有相邻 1 的状态),最多 个,对于 是 4096,但合法状态少得多(斐波那契数列增长,约 377 个)。
- 对于每一行,再从中筛选出符合该行土地肥沃条件的状态。
- 转移时枚举当前行状态和上一行状态,复杂度 ,其中 是合法状态数,约 400,,计算量很小。
实现步骤
- 读入 和土地矩阵。
- 将每行的土地状况压缩为一个整数 :从左到右,第 位为 1 表示肥沃。
- 预处理所有合法状态 :遍历 到 ,筛选出没有相邻 1 的状态(即
(s & (s >> 1)) == 0)。 - 对于每一行 ,从 中筛选出符合该行土地的状态 :满足
(s & ~row[i]) == 0。 - 动态规划:
- 。
- 对于 从 1 到 :
- 对于当前行状态 :
- $dp[i][s] = \sum_{prev \in state[i-1]} dp[i-1][prev]$,其中 。
- 对于当前行状态 :
- 答案 。
复杂度
- 状态数 ,,可接受。
- 转移 ,,,计算量约 ,很快。
总结
本题是状态压缩 DP 的入门题,关键点在于将行状态压缩为二进制,并检查合法性。