例如acwing291
思路(其实是结合老师的课件悟出来的
状态: F[i][j]表示前i-1列放满了 第i列横着放的矩形状压为j之后的方案数
转移:F[i][j]=sigema(F[i-1][k]) ; k枚举i-1列的横条 合法条件:k&j==1 对于j 连续的空位个数为偶数 否侧无法用竖条赛满
但是这里我有个问题 我的1*2肯定是从1 * 1 转移过来的 但是1 * 1 显然不合法为0 那么1 * 2 是怎么转移出来的
然后代码瞎写的 请求dalao指点
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=13;
int n,m;
int f[N][(1<<N)];//前i-1列已经摆放好 且从i-1列延伸到第i列的长条状态为j 的方案数 因此我们将横条的状态进行状压
signed main()
{
while(1)
{
scanf("%lld%lld",&n,&m);
if( !n && !m ) return 0;
memset(f,0,sizeof f);
f[0][0]=1;
for(int i=2;i<=m;i+=2) f[i][1]=1;//预处理?
for(int i=1;i<=m+1;i++) //阶段 枚举前i列
{
for(int j = 0 ; j < (1<<n) ; ++j ) //状态
{
for(int k = 0 ; k < (1<<n) ; ++k ) // 决策
{
int res=0;
int t=k;
bool flag=0;
do
{
if(!(t&1)) res++;
else
{
if(res&1) // 连续的空位为偶数 否侧无法填完
{
flag=1;
break;
}
res=0;
}
t>>=1;
} while(t);
if(res&1) continue;
if(flag) continue;
if( ( j & k ) == 0 ) //第i-2延伸的与i-1延伸的不重复
{
// printf("J:%lld K:%lld I:%lld \n",j,k,i);
f[i][j]+=f[i-1][k] ;
}
}
// printf("I:%lld J:%lld Val:%lld\n",i,j,f[i][j]);
}
}
printf("%lld\n",f[m+1][0]);//前m列 顺序已确定 延伸到m+1为0
// puts("");
}
}
//f[i][j]=sigema(f[i][k]) 其中 k 为合法状态