题目大意:在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子
题解: f[i][j][k]表示前i行共放了j个国王,第i行状态为k的方案数
设计函数判断一行/两行可行
一行可行只需要判断二进制是否有相邻的1
两行还需要判上下相邻……参悟一下……
处理出第一行的可行情况
l可行,t可行,两行可行,tmp=cnt(l),则有
f[i][j][l]+=f[i−1][j−tmp][t]
我的收获:二进制强啊
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m,k;
long long ans,f[15][100][1024];
inline bool ok(int x,int y){return !((x&(y<<1))||(x&(y>>1))||(x&y));}//判断两行可行,左右上下
inline bool ck(int x){return !((x&(x<<1))||(x&(x>>1)));}//判断一行状态可行
inline int cnt(int x){int i,ret=0;for(i=x;i;i-=i&(-i),ret++);return ret;}//返回x二进制中1的个数
void work()
{
for(int i=2;i<=n;i++)
for(int j=0;j<=m;j++)
for(int l=0;l<=k;l++)
if(ck(l)&&j>=cnt(l))
{
int tmp=cnt(l);
for(int t=0;t<=k;t++)
if(ck(t)&&ok(l,t)) f[i][j][l]+=f[i-1][j-tmp][t];
}
for(int i=0;i<=k;i++) ans+=f[n][m][i];
printf("%lld\n",ans);
}
void init()
{
scanf("%d%d",&n,&m);
k=(1<<n)-1;
for(int i=0;i<=k;i++) if(ck(i)) f[1][cnt(i)][i]=1;
}
int main()
{
init();
work();
return 0;
}