【洛谷P1896】[SCOI2005]互不侵犯
传送门
题目描述
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
注:数据有加强(2018/4/25)
输入格式
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
输出格式
所得的方案数
输入输出样例
输入 #13 2
输出 #116
挺好一模板
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 12;
long long dp[N][1<<N][N*N];//前i行,状态为j,放了k个国王
int n,k,cnt;
long long ans;
int s[1<<N],num[1<<N];
int main()
{
scanf("%d%d",&n,&k);
for(int i=0;i<(1<<n);i++)
{
if( i&(i<<1) ) continue;
int sum=0;
for(int end=0;end<n;end++)
if( i&(1<<end) ) sum++;
s[++cnt]=i;
num[cnt]=sum;
}
//预处理
dp[0][1][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=cnt;j++) //枚举状态,但其实这里枚举的是状态的编号
for(int p=0;p<=k;p++)
{
if(p>=num[j])
for(int end=1;end<=cnt;end++)
{
if( !(s[end]&s[j]) && !(s[end]&(s[j]<<1)) &&
!(s[end]&(s[j]>>1)) )
dp[i][j][p]+=dp[i-1][end][p-num[j]];
}
}
for(int i=1;i<=cnt;i++)
ans+=dp[n][i][k];
printf("%lld",ans);
return 0;
}