人生中的第一道状压dp(照着题解写的(捂脸))
先dfs预处理出每种情况下的二进制(状压不是用01描轮廓吗),然后枚举每行的选哪个,不用考虑他的上一行,因为这行是从上一行转移下来的,我们只需要判断和下一行冲不冲突,不冲突就累加答案
初始化时第一行的美种情况的方案数都是1,最后去最后一层累加答案
代码(从头到尾抄了一遍,虽然不是直接交的题解,但是还是好羞耻(捂脸))
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=2050;
long long int f[10][M][100];
int push[M],get[M];
int n,m,cnt=0;
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void dfs(int emm,int sum,int x)
{
if (x>=n){get[++cnt]=emm;push[cnt]=sum;return ;}//到了最底层
dfs(emm,sum,x+1);//不选当前点,那么找它下一个
dfs(emm+(1<<x),sum+1,x+2);//选了当前点,那么下一个不能选,跳过
return ;
}//处理每种情况
int main()
{
n=read();m=read();
dfs(0,0,0);
for (int i=1;i<=cnt;i++)
f[1][i][push[i]]=1;//第一层的每种方案都是一种
for (int i=2;i<=n;i++)
for (int j=1;j<=cnt;j++)
for (int k=1;k<=cnt;k++)
if (get[j]&get[k]) continue;//冲突
else if ((get[j]<<1)&get[k]) continue;//冲突
else if (get[j]&(get[k]<<1)) continue;//冲突
else for(int e=m;e>=push[j];e--) f[i][j][e]+=f[i-1][k][e-push[j]];//累加
long long int ans=0;
for (int i=1;i<=cnt;i++) ans+=f[n][i][m];//在最底层统计答案
cout<<ans;
return 0;
}