#Description
给你一个地图,叫你放东西。
0表示不能放,1表示可以放。
东西不能相邻放,问有多少种放法?
#= =
一开始黄队长和我说是状压DP。受前几天最优配对问题的影响,以为把所有情况状态压缩。一看数据2^(12*12)肯定是伤不起的。然后就GG。不知道怎么做
于是请教黄队长。
原来是每一行压缩。
#Algorithm
于是得到状态
dp[i][j] 表示第i行排列成j的总方案数
状态转移
dp[i][j] = dp[i - 1][k]
k表示所有和j不两个竖着连一起的状态
两个竖着不连一起显然是 j & k > 0
对于j,要考虑j必须满足当前行的状态,aka,不能再不能放的地方放。
j & ~g[i] > 0表示在不能放的地方上放了 continue;
j自己本身不能两个1连起来,j & (j << 1)这样就可以判断
最后把最后一行加起来就是ans
#Code
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n, m;
const int MAXN = 12;
const int MAXM = 12;
const int MOD = 1e8;
int g[MAXN];
int dp[MAXN][1<<MAXM];
void solve()
{
memset(g, 0, sizeof(g));
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; i++) {
g[i] = 0;
for (int j = 0; j < m; j++) {
int x;
scanf("%d", &x);
g[i] += (x << j);
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < (1 << m); j++) {
if (j & (~g[i])) continue; //与此行不符
if (j & (j << 1)) continue; //两个相连
if (i == 0) {
dp[i][j] = 1;
continue;
}
for (int k = 0; k < (1 << m); k++) {
if (j & k) continue; //竖着两个一样
dp[i][j] = (dp[i][j] + dp[i - 1][k]) % MOD;
}
}
}
int ans = 0;
for (int i = 0; i < (1 << m); i++) {
ans = (ans + dp[n - 1][i]) % MOD;
}
cout << ans << endl;
}
int main()
{
//freopen("in.txt", "r", stdin);
while (scanf("%d%d", &n, &m) != EOF) {
solve();
}
}