解题思路:
状态表达式 : dp[i][s] 表示第i层压缩状态位s的总种法(s的种法是符合土地要求的)
转移表达式 : 当 s1 和 s2 都满足种植条件,且两者共存【check(s1) && check(s2) && (s1 & s2) == 0】,则有 dp[i][s1] += dp[i][s2]
用 id[i] 数组表示第i行能种的压缩状态, 如 00101, id[i] = 5
利用如下方式遍历id[i]的子集即可(带有空集)
int s=id[i];
do{
// ...
s=(s-1)&id[i];
} while(s!=id[i]);
C++ 代码
#include <iostream>
using namespace std;
const int N = 1 << 13 + 10;
const int M = 14, MOD = 1e8;
int n, m, t;
// id[i] 表示第 i 行的状态数,2进制1表示可种
int id[M];
// dp[i][s] 表示第i层压缩状态位s的总种法(s的种法是符合土地要求的)
long long dp[M][N];
/**
* 判断数字s的位状态,保证相邻两位没有状态都是1(相邻的土地不能同时种植玉米)
*/
bool check(int s) {
// 遍历各个位子
for(int i=0;i<M;i++) {
// 如果当前位数i是1,且i+1位也是1,那么会导致两个状态都是1,显然是不符合要求的
if((s >> i & 1) && (s >> (i+1) & 1)) return false;
}
return true;
}
int main() {
cin >> n >> m;
for(int i=1;i<=n;i++) {
for(int j=0;j<m;j++) {
cin >> t;
id[i] = (id[i] << 1) + t;
}
}
// 0 层状态 0 有一种种法
dp[0][0] = 1;
long long ans = 0;
for(int i=1;i<=n;i++) {
int pre = id[i-1], cur = id[i];
// 枚举当前层的所有子状态
int s1=cur;
do{
// 枚举上一层的所有子状态
int s2=pre;
do{
// 如果满足两层之间的状态
if(check(s1) && check(s2) && (s1 & s2) == 0) {
dp[i][s1] = (dp[i][s1] + dp[i-1][s2]) % MOD ;
}
s2=(s2-1)⪯
} while(s2!=pre);
if(i == n) ans = (ans + dp[i][s1]) % MOD;
s1=(s1-1)&cur;
} while(s1!=cur);
}
cout << ans << endl;
return 0;
}