题面
题目描述
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
输入格式
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
输出格式
一行,一个整数,表示答案。
题解
还是状态压缩裸题。
f[i][j][k]代表第i行的状态是k,已经放了j个king的答案。
我们先要考虑合法的状态。
因为king的攻击方式是八个方向各一个格子,所以我们可以得到,如果i&(i<<1)活着i&(i>>1)其中一个不为0,那么i这个状态就是不合法的。flag[i]=true表示合法
我们顺带预处理出状态i中有几个1的数组num[i]。
状态转移方程
(R&L==0)&&((R<<1)&L==0)&&((R>>1)&L==0)
code
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int num=0;
char c=' ';
bool flag=true;
for(;c>'9'||c<'0';c=getchar())
if(c=='-')
flag=false;
for(;c>='0'&&c<='9';num=num*10+c-48,c=getchar());
return flag ? num : -num;
}
const int maxn=11;
int n,k,num[1<<maxn];
long long f[maxn][maxn*maxn][1<<maxn];
bool flag[maxn];
void yuchuli(){
for(int i=0;i<1<<n;i++)
if(!(i&(i<<1))){
int count=0;
flag[i]=true;
for(int j=0;j<n;j++)
if(i>>j&1)count++;
num[i]=count;
f[1][num[i]][i]=1;
}
}
void dp(){
for(int i=2;i<=n;i++)
for(int j=0;j<=k;j++)
for(int R=0;R<1<<n;R++)
if(flag[R]&&num[R]<=j)
for(int L=0;L<1<<n;L++)
if(flag[L])
if((R&L)||((R<<1)&L)||((R>>1)&L))
continue;
else
f[i][j][R]+=f[i-1][j-num[R]][L];
}
int main(){
n=read();k=read();
yuchuli();
dp();
long long ans=0;
for(int i=0;i<1<<n;i++)
ans+=f[n][k][i];
printf("%lld\n",ans);
return 0;
}