状压dp题
每一行放不放国王可以用1010010来表示
所以每一行的状态可以看成一个二进制数
这样n是小于9的,可以把小于2^n,(因为2^9是512,很小)的数打表存出来
把自己和自己冲突的筛掉,然后记下有多少1,判断他们是否冲突。
预处理完了,接下来是dp了
动态转移方程:
dp[i][q+t[j]][a[j]]=Σdp[i-1][q][a[i]]
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<stdlib.h>
using namespace std;
int cnt,ans;
int n,k,a[19999],dp[19][199][600];
int f[1999][1999],t[19999];
int main(){
scanf("%d%d",&n,&k);
int w=(1<<n)-1;
for(int i=0;i<=w;i++)
if((((i>>1)&i)==0)&&(((i<<1)&i)==0))
a[++cnt]=i;
for(int i=1;i<=cnt;i++)
{
int x=a[i];
while(x)
{
t[i]+=(x&1);
x/=2;
}
}
for(int i=1;i<=cnt;i++)
for(int j=1;j<=cnt;j++)
{
if(((a[i]&a[j])==0)&&(((a[i]>>1)&a[j])==0)&&(((a[i]<<1)&a[j])==0))
f[i][j]=1;
}
for(int i=1;i<=cnt;i++)dp[1][t[i]][a[i]]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<=cnt;j++)
for(int q=1;q<=cnt;q++)
{
if(f[j][q])
for(int p=t[j];p+t[q]<=k;p++)
{
dp[i][p+t[q]][a[q]]+=dp[i-1][p][a[j]];
}
}
for(int i=1;i<=cnt;i++) ans+=dp[n][k][a[i]];
printf("%d",ans);
}