10.9
状压,用状态s表示一行中填过的地雷的状态。将每一行能填的数字压缩为一个状态T,我们需要枚举T的子集。
枚举子集代码如下:
for(inti=T;; i=(i-1)&T)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define N 13
#define M 5000
#define mod 100000000
using namespace std;
int n, m, lim;
LL f[N][M];//f[i][j]表示第i行状态为j时的方案数。
int str[M], sta[M], cnt;
int main(){
freopen ("chess.in", "r", stdin);
freopen ("chess.out", "w", stdout);
scanf("%d%d", &n, &m);
f[0][1] = 1;
lim = (1 << m) - 1;
for(int i=1; i<=n; i++){
int cc = 0, d;
for(int j=1; j<=m; j++){
scanf("%d", &d);
cc = (cc << 1) + d^1;
}
sta[i] = cc;
}
/*for(int i=1; i<=n; i++)
printf("YY %d\n", sta[i]);*/
for(register int i=0; i<=lim; i++){
if(( i&(i<<1) ) == 0){//没有两个相邻
str[++cnt] = i;//储存状态
}
}
/*for(int i=1; i<=cnt; i++)
printf("YY %d\n", str[i]);*/
for(int i=1; i<=n; i++){
for(register int j=1; j<=cnt; j++){
for(register int k=1; k<=cnt; k++){
if( !(str[j] & sta[i-1]) && !(str[k] & sta[i]) && !(str[j] & str[k]) ){//判断j,k状态间是否能够转移
f[i][k] = (f[i][k] + f[i-1][j]) % mod;
}
//printf("YY %d %d %d\n", i, str[k], f[i][k]);
}
}
}
LL ans = 0;
for(register int i=1; i<=cnt; i++)
if( !(str[i] & sta[n]) ) ans = (ans + f[n][i]) % mod;
cout << ans << endl;
return 0;
}