#include <cstring>//有memset要用这个头文件
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 12, M = 1 << N; //N和M为矩形的行数和列数
int n, m;
long long f[N][M];//j在第i列表示存储了第i-1列有没有伸出到第i列的横着摆放的长方形 有1 无0
//如果有n行就储存n个二进制数
bool st[M]; //st数组用来储存bool类型
int main()
{
int n, m;
while (cin >> n >> m, n || m) //n||m为0停止输入 n行m列
{
memset(f, 0, sizeof f); //每一次都需初始化 因为有多组数据
for (int i = 0; i < 1 << n; i++)//枚举每一行 1<<5=32 若有5行就有32种可能 00001~11111
{
st[i] = true;
int cnt = 0; //cnt表示当前这一列连续0的个数
for (int j = 0; j < n; j++)//枚举每一行
if (i >> j & 1)//表示第i种情况所代表的二进制数中的第j位/第j行
{
if (cnt & 1) st[i] = false;//cnt为奇数不合法 存在连续奇数个0
cnt = 0;
}
else cnt++;
if (cnt & 1) st[i] = false;//判断最后一个cnt值是否合法
}
//上面整个for循环就是将每一列合法的二进制数用st数组标记 方便后续dp的判断
//每一列合法:每一列不存在连续奇数个0 100001、00100之类的
//dp部分
f[0][0] = 1;//初始化 1个方案数
for (int i = 1; i <= m; i++)//枚举每一列 第0列无需枚举
for (int j = 0; j < 1 << n; j++)//枚举第i列的每个方案
for (int k = 0; k < 1 << n; k++)//枚举第i-1列的所有方案
if ((j & k) == 0 & st[j | k]) //是否状态转移的条件
f[i][j] += f[i - 1][k];
cout << f[m][0] << endl;
//总共m列 0~m-1 第m列的j为0 说明第m-1列没有伸到第m列的矩形 说明该拜访合法
}
return 0;
}
状压dp--
最新推荐文章于 2024-05-31 14:42:05 发布