不懂,若至 DP 题为什么有资格评蓝,顶多黄橙吧。
设 $dp_{i,S}$ 表示前 $i$ 行,最后一行状态为 $S$ 的方案数。
转移的时候枚举上一行状态 $T$,保证 $S,T$ 满足题目条件,且内部没有相邻 $1$,且 $S,T$ 上下没有相邻 $1$(and 运算)即可。
可以滚动优化,但没有必要。
时间复杂度 $O(n \times 2^{2n})$。
#include <bits/stdc++.h>
using namespace std;
const int N = 20, M = (1 << 12) + 5, mod = 1e8;
int n, m;
int st[N], dp[N][M];
bool check(int S, int i) {
return (S & st[i]) == S; //子集
}
bool check2(int S) {
for (int i = 0; i < m - 1; i++)
if ((S & (1 << i)) && ((S & (1 << i + 1)))) return 0;
return 1;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
for (int j = 0, x; j < m; j++) {
scanf("%d", &x);
if (x) st[i] |= (1 << j);
}
memset(dp, 0, sizeof dp);
dp[0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int S = 0; S < (1 << m); S++) {
if (!check2(S)) continue;
for (int T = 0; T < (1 << m); T++) {
if (!check2(T)) continue;
if (check(S, i) && check(T, i - 1) && (S & T) == 0) (dp[i][S] += dp[i - 1][T]) %= mod;
}
}
}
long long ans = 0;
for (int i = 0; i < (1 << m); i++) (ans += dp[n][i]) %= mod;
printf("%lld\n", ans);
return 0;
}