原题地址:http://poj.org/problem?id=2411
题意:给一个n*m的矩形,你有若干1*2的小矩形,问你有多少种家那个这个矩形填满的方法。
思路:主要参考了大佬的博客;
定义01状态:定义横放的砖块为11,竖放的砖块01
dp状态:定义dp[i][j]表示第i行状态为j的方案数
状态转移:dp[i][j]+=
dp初始化:第一行只要连续的1是偶数个就行了,只要满足dp[1][k] (k是某一状态)=1
注意一个long long和位运算的优先级顺序
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
int n, m;
ll dp[15][2500];
//dp[i][j]表示第i行状态为j的时候的方案数量
int init(int s) { //初始化dp数组
int i = 0;
while(i < m) {
if((s & 1 << i) == 0) i++;
else {
if((s & 1 << (i + 1))==0) return 0;
if(i == m - 1) return 0;
else i += 2;
}
}
return 1;
}
int solve(int x, int y) {
//判断x是否是合法的
//判断的时候如果砖头是横着铺的,那么一定是横着的第一块,
//因为如果是第二块的话,那么一定会在上一次就会被判断
int i = 0;
while(i < m) {
if((x & 1 << i) == 0) {
if((y & 1 << i)==0) return 0;
i++;
} else {
if((y & 1 << i) == 0) i++;
else {
if(i == m - 1 || (x & 1 << (i + 1)) == 0) return 0;
if((y & 1 << (i + 1)) == 0) return 0;
i += 2;
}
}
}
return 1;
}
int main() {
while(~scanf("%d%d", &n, &m), n + m) {
memset(dp,0,sizeof(dp));
if(n < m) swap(n, m);
int sum = (1 << m);
for(int s=0;s<sum;s++) {
if(init(s)) dp[1][s]=1;
}
for(int i = 2; i <= n; i++) {
for(int j = 0; j < sum; j++) {
for(int k = 0; k < sum; k++) {
if(solve(j, k)) dp[i][j] += dp[i - 1][k];
}
}
}
printf("%lld\n", dp[n][sum - 1]);
}
return 0;
}