Description
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。
Input
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数。
Sample Input
3 2
Sample Output
16
分析
其实我们可以用一张美妙的表来解决这道题
mdzz,少了一个括号秘制调了一天。。。好贱啊。
先跑一边搜索,把所有的合法的状态跑出来,然后再跑一遍,把所有的合法的状态组合找出来,然后可以跑状压dp了,我们用F[i][j][k]表示前i行,共用了j个旗子,状态为k时的方案数。其中num[i]表示状态为i时用了多少棋子。
代码
/**************************************************************
Problem: 1087
User: ypxrain
Language: C++
Result: Accepted
Time:72 ms
Memory:10084 kb
****************************************************************/
#include <bits/stdc++.h>
#define N 1000
#define M 10
bool l[N];
bool map[N][N];
int num[N];
long long f[M][M*10][N];
long long ans,tot;
int n,k;
int read()
{
int k=1,x=0;
char ch;
ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
k=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*k;
}
void initl()
{
for(int i=0;i<tot;++i)
{
if((i&(i<<1))==0)
{
l[i]=true;
int t=i,cnt=0;
while(t)
{
cnt+=(t&1);
t>>=1;
}
num[i]=cnt;
f[1][cnt][i]=1;
}
}
}
void initm()
{
for(int i=0;i<tot;++i)
{
if(!l[i])
continue;
for(int j=0;j<tot;++j)
{
if(!l[j])
continue;
if(!(i&j) && !((i<<1)&j) && !((i>>1)&j))
map[i][j]=true;
}
}
}
void dp()
{
for(int i=2;i<=n;++i)
{
for(int j=0;j<=k;++j)
{
for(int now=0;now<tot;++now)
{
if(num[now]>j)
continue;
if(!l[now])
continue;
for(int nowk=0;nowk<tot;nowk++)
{
if(!l[nowk])
continue;
if(!map[now][nowk])
continue;
if(num[now]+num[nowk]>j)
continue;
f[i][j][now]+=f[i-1][j-num[now]][nowk];
}
}
}
}
}
void sum()
{
for(int i=0;i<tot;++i)
{
if(!l[i])
continue;
ans+=f[n][k][i];
}
}
int main()
{
n=read();
k=read();
tot=1<<n;
initl();
initm();
dp();
sum();
std::cout<<ans<<std::endl;
}