方格填充
题目描述
将高为 H,宽为 W 的棋盘分割成若干个宽和高分别为 1 和 2 的长方形,有多少种方案。
输入描述
第一行为 H(1≤H≤11),W(1≤W≤11)。
输出描述
输出方案数。
测试样例
输入:
2 2
输出:
2
题解
用状压DP,用一个数字来表示当前行的每一个虚拟格子的状态
注意这里的遍历方案数的循环,循环截至的条件是 “<” 而不是小于等于(全 0 也算一种,n 种物品全选的话他表示的方案总数的二进制换成十进制也是 2 n − 1 2^n -1 2n−1 ) for (ll s1 = 0; s1 < (1 << W); s1++)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[5000][5000] = {0};
bool check(ll s, ll m) //判断是不是连续的0
{
ll count = 0;
for (ll i = 0; i < m; i++)
{
if ((s & (1 << i)) != 0)
{
if ((count & 1) != 0)
return false;
else
count = 0;
}
else
count++;
}
if ((count & 1) != 0) //加这一步是为了防止最高位的那些0由于更高位没有1就测不到
return false;
return true;
}
int main()
{
ll H, W;
cin >> H >> W;
dp[0][0] = 1;
for (ll i = 1; i <= H; i++)
for (ll s1 = 0; s1 < (1 << W); s1++) //当前列方案
for (ll s2 = 0; s2 < (1 << W); s2++) //上一列方案
if ((s1 & s2) == 0 && check(s1 | s2, W))
dp[i][s1] += dp[i - 1][s2];
cout << dp[H][0];
return 0;
}