题目描述
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
输入输出格式
输入格式:
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
输出格式:
所得的方案数
输入输出样例
题解
状压dp入门题。关于状压dp的基本概念在此不赘述。
#include<cstdio>
using namespace std;
int n,k,num[512];
long long f[10][82][512];//十年OI一场空 不开longlong见祖宗
bool flag[512]={0};
long long ans=0;
void init()//预处理
{
for(int i=0;i<(1<<n);i++)枚举一行可能存在的状态是否合法
{
if(!(i&(i<<1)))
{
flag[i]=true;
int t=i;
while(t)如果该状态合法 则计算该状态中国王的个数
{
num[i]+=(t&1);
t>>=1;
}
f[1][num[i]][i]=1;
}
}
}
int main()
{
scanf("%d%d",&n,&k);
init();
for(int i=2;i<=n;i++)//第一行已经算过了 所以从第二行开算
for(int j=0;j<=k;j++)//k为前i行共有的国王数
for(int now=0;now<(1<<n);now++)//枚举第i行的状态
{
if(!flag[now]||num[now]>j)continue;//该状态不合法 则跳过
for(int pre=0;pre<(1<<n);pre++)//暴力枚举上一行的状态 如果上一行状态与
当前行状态冲突 则跳过
{
if(!flag[pre]||(now&pre)||((now<<1)&pre)||((now>>1)&pre))continue;
f[i][j][now]+=f[i-1][j-num[now]][pre];//状态转移方程
}
}
for(int i=0;i<(1<<n);i++)ans+=f[n][k][i];//枚举最后一行的状态 方案数相加 注意要开longlong
printf("%lld",ans);
}