#(mathcal{color{red}{Description}})
农场主(John)新买了一块长方形的新牧场,这块牧场被划分成(M)行(N)列((1 ≤ M ≤ 12; 1 ≤ N ≤ 12)),每一格都是一块正方形的土地。
(John)打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。
遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是(John)不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。
(John)想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)
#(mathcal{color{red}{Solution}})
(emmm)这题是我上周做的……害得我都忘了当时犯了什么纸张错误= =
一看就是状压(DP)
我发现原来状压DP的转移都贼简单……(emmm)我的意思是暂时,起码迄今为止我做过的状压题里都挺简单(做过的题(leq 5))……
然后我们可以考虑一开始把(0)的位置记成(1),然后我们判断的时候只要看它&起来会不会为真就行……
有个坑点就是
for(i = 1; i <= N; i ++)
for(j = 1; j <= M; j ++){
cin >> c ;
if (c == '0')
Line[i] |= (1 << (j - 1)) ;
}
这是读入……然后我把(1 << (j - 1))给写成了(1 << j)还觉得挺对(emmmm)
嗯,实践出真知,劳动创造财富左移运算是移动几位……嘤嘤嘤比如你(1)左移(3)位其实其实来到的是第(4)位上……
哇塞我可真是个蒟蒻……
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std ;
typedef long long ll ;
const int MAXN = 210 ;
const ll mod = 100000000 ;
char c ; ll ans, i, j, k, Mx ;
ll N, M, Line[20], dp[20][4080] ;
int main(){
cin >> N >> M ;
dp[0][0] = 1 ;
Mx = (1 << M) - 1 ;
for(i = 1; i <= N; i ++)
for(j = 1; j <= M; j ++){
cin >> c ;
if (c == '0')
Line[i] |= (1 << (j - 1)) ;
}
for(i = 1; i <= N; i ++)
for(j = 0 ; j <= Mx; j ++){
if((j & Line[i]) || (j & (j >> 1)) ) continue ;
for(k = 0 ; k <= Mx; k ++){
if((j & k) || (k & Line[i - 1]) || (k &(k >> 1))) continue ;
dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod ;
}
}
for(i = 0; i <= Mx; i ++) ans = (ans + dp[N][i]) % mod ;
cout << ans % mod ;
}