思路
有一种1x2的砖块,问有多少种填满的方案。
砖块只能横着放或竖着放,设横着放为1 1,竖着为
1
0
_1^0
10,
显然上下不能有同位的0,并且每一行的连续1的个数减去上一行对应位置的0的个数后不能为奇数,
满足条件的就
d
p
[
i
]
[
j
]
+
=
d
p
[
i
−
1
]
[
k
]
dp[i][j]+=dp[i-1][k]
dp[i][j]+=dp[i−1][k].最后一行一定是填满的,所以答案是
d
p
[
h
]
[
(
1
<
<
w
)
−
1
]
.
dp[h][(1<<w)-1].
dp[h][(1<<w)−1].
要让同位没有相同0,那么
j
∣
k
后
每
一
位
都
应
该
是
1
,
所
以
k
∣
j
=
(
1
<
<
w
)
−
1
j|k后每一位都应该是1,所以k | j=(1<<w)-1
j∣k后每一位都应该是1,所以k∣j=(1<<w)−1。判断减去0后1的奇偶可以令x=j&k,
这样原来的1会变成0,就相当于减去了对应的1。
还有当h,w都为奇数的时候直接输出0就行了,我tle加上这个判断就过了。
代码
#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <queue>
#include <sstream>
#include <string>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define reps(i, a, b) for (int i = a; i >= b; i--)
#define mk make_pair
using namespace std;
const int N = 1e2 + 10;
const int M = 17;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
typedef long long ll;
ll dp[M][1<<M];
inline int init(int j)
{//第一行没有上一行,所以只要自己能填满并且不冲突就行
int x=j;
int cnt=0;
while (x){
if(x%2==1)cnt++;
else{
if(cnt&1)return 0;
cnt=0;
}
x>>=1;
}
if(cnt&1)return 0;
else return 1;
}
inline bool check(int x,int y)
{//判断减去0对应位置的1后,1的个数的奇偶
int j=(x&y);
int cnt=0;
while (j){
if(j%2==1)cnt++;
else{
if(cnt&1)return 0;
cnt=0;
}
j>>=1;
}
if(cnt&1)return 0;
else return 1;
}
void solve(int h,int w)
{
if((h&1)&&(w&1)){//全是奇数直接输出0.
puts("0");
return;
}
int M=(1<<w)-1;
rep(j,0,M){
dp[1][j]= init(j);
}
rep(i,2,h){
rep(j,0,M){
rep(k,0,M){
if((k|j)!=M)continue;
if(!check(j,k))continue;
dp[i][j]+=dp[i-1][k];
}
}
}
printf("%lld\n",dp[h][M]);
}
int main()
{
int h,w;
while (~scanf("%d%d",&h,&w)) {
if(h==0&&w==0)break;
memset(dp,0,sizeof dp);
solve(h, w);
}
return 0;
}