题目描述
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
输入输出格式
输入格式:只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
输出格式:所得的方案数
输入输出样例
输入样例#1:
3 2
输出样例#1:
16
最近爱写状压dp,就又找了一道题。
压缩行,有king是1,没有是0.
判断可行,就是将上一行与这一行按位与,接着左移,右移。
剩下的就是简单的dp了。
16
最近爱写状压dp,就又找了一道题。
压缩行,有king是1,没有是0.
判断可行,就是将上一行与这一行按位与,接着左移,右移。
剩下的就是简单的dp了。
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=10;
int n,k,a[10005],b[10005],tp;
long long f[N][N*N][1<<N],ans;
//第i行,一共摆放了j个king,第i行的摆放情况是g
void dfs(int num,int lst,int at,int bt)
{
if(num==n)
{
++tp;
a[tp]=at;
b[tp]=bt;
return ;
}
dfs(num+1,lst,at,bt);
if(num-lst>=2)
{
at|=(1<<num);
bt++;
dfs(num+1,num,at,bt);
}
}
int main()
{
scanf("%d%d",&n,&k);
dfs(0,-2,0,0);
f[0][0][0]=1;
int end=(1<<n)-1;
for(int i=1;i<=n;i++)
for(int j=0;j<=k;j++)
for(int g=0;g<=end;g++)
if(f[i-1][j][g]>0)
for(int h=1;h<=tp;h++)
if((a[h]&g)==0&&(a[h]&(g<<1))==0&&(a[h]&(g>>1))==0&&j+b[h]<=k)
f[i][j+b[h]][a[h]]+=f[i-1][j][g];
for(int i=0;i<=end;i++)
ans+=f[n][k][i];
printf("%lld\n",ans);
return 0;
}