洛谷传送门
BZOJ传送门
题目描述
在 N × N N×N N×N的棋盘里面放 K K K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共 8 8 8个格子。
输入输出格式
输入格式:
只有一行,包含两个数 N N N, K K K ( 1 ≤ N ≤ 9 , 0 ≤ K ≤ N ∗ N 1 \le N \le 9, 0 \le K \le N * N 1≤N≤9,0≤K≤N∗N)
输出格式:
所得的方案数
输入输出样例
输入样例#1:
3 2
输出样例#1:
16
解题分析
状压每一行的状态并枚举上一行的状态进行转移, 因为每行单独的合法状态其实个数很少, 可以先预处理出来进行转移。
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <cctype>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
ll dp[10][512][512];
int cnt[512], n, lim, tot, stat[512];
void pre()
{
int bd = (1 << n) - 1;
for (R int i = 0; i <= bd; ++i)
{
if(i & (i << 1) || (i & (i >> 1))) continue;
stat[++tot] = i; cnt[tot] = __builtin_popcount(i);
dp[1][cnt[tot]][tot] = 1;
}
}
int main(void)
{
scanf("%d%d", &n, &lim);
pre(); R int i, j, k, tar, bd, o;
for (i = 2; i <= n; ++i)
{
for (j = 0; j <= lim; ++j)
{
for (k = 1; k <= tot; ++k)
{
tar = j - cnt[k];
if(tar < 0) continue;
for (o = 1; o <= tot; ++o)
{
if((!(stat[o] & stat[k])) && (!(stat[o] & (stat[k] << 1))) && (!(stat[o] & (stat[k] >> 1))))
dp[i][j][k] += dp[i - 1][j - cnt[k]][o];
}
}
}
}
ll ans = 0;
for (R int i = 1; i <= tot; ++i) ans += dp[n][lim][i];
printf("%lld", ans);
}