https://www.luogu.org/problemnew/show/P1896
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
输入格式:
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
输出格式:
所得的方案数
思路:设f(i,j,k):前i行,第i行压位后为state[]第j个元素,目前已经放了k个国王,对应的方案数。
同一行的攻击(等价于任意两点不相邻)开始时就预处理好放在state[]中
上下的攻击分别判断a&b,a<<1&b,a&b<<1。
转移是比较裸的。
要开long long
#include<bits/stdc++.h>
using namespace std;
#define mod 100000000
int n,k;
int state[1<<10],tot;
long long f[10][1<<10][100];//第二维是在state[]中的下标,而非实际二进制
int main()
{
// freopen("input.in","r",stdin);
cin>>n>>k;
for(int i=0;i<(1<<n);i++)if(!(i&(i<<1)))state[tot++]=i;
for(int i=0;i<tot;i++)
{
int s=state[i],cnt=0;
for(int j=0;j<n;j++)if((1<<j)&s)cnt++;
f[0][i][cnt]++;
}
for(int i=1;i<n;i++)
{
for(int j=0;j<tot;j++)
{
for(int s=0;s<tot;s++)
{
if((state[s]&state[j])==0&&(state[s]&(state[j]<<1))==0&&((state[s]<<1)&state[j])==0)
{
int cnt=0;
for(int l=0;l<n;l++)if((1<<l)&state[j])cnt++;
for(int p=cnt;p<=k;p++)f[i][j][p]+=f[i-1][s][p-cnt];
}
}
}
}
long long ans=0;
for(int j=0;j<tot;j++)ans+=f[n-1][j][k];
cout<<ans<<endl;
exit(0);
}