Description
在n*n(1<=n<=10)的棋盘上放k(0<=k<=n*n)个国王(可攻击相邻的8 个格子),求使它们无法互相攻击的方案总数。
Input
输入文件仅一行为两个整数n和k。
Output
输出文件仅一行为方案总数,若不能够放置则输出0。
Sample Input
3 2
Sample Output
16
Hint
【样例输入2】
4 4
【样例输出2】
79
一眼状压,用1表示国王(话说真的不知道这个翻译在干什么,到底是国王还是骑士啊……)
但是不能裸上,合法状态事实上并不多,预处理一下每行的合法状态,即不允许相邻的1,存在数组s[]里
方程:当i - 1行的状态为s[p],i行的状态为s[j],且s[j]和s[p]不冲突时,f[i][j][k] += f[i - 1][p][k - sum[j]]; 其中sum[]表示该状态1的个数,f[i][j][k]表示前i行中第i行为状态s[j]且共有k个1
#include <bits/stdc++.h>
#define lowbit(x) x & -x
using namespace std;
const int MAXS = 1050;
const int MAXN = 11;
const int INF = 0x3f3f3f3f;
template <typename T> inline void read(T &x) {
int ch = getchar();
bool fg = false;
for (x = 0; !isdigit(ch); ch = getchar()) {
if (ch == '-') {
fg = true;
}
}
for (; isdigit(ch); ch = getchar()) {
x = x * 10 + ch - '0';
}
if (fg) {
x = -x;
}
}
typedef pair<int, int> pii;
typedef long long LL;
int s[MAXS], cnt, n, ALL, sum[MAXS], K;
LL f[MAXN][MAXS][MAXN * MAXN];
bool Legal(int i) {
return !(i & (i << 1));
}
void Init() {
ALL = (1 << n) - 1;
for(int i = 0; i <= ALL; i++) {
if(Legal(i)) {
int x = i;
s[++cnt] = i;
while(x) x -= lowbit(x), sum[cnt]++;
}
}
}
bool chk(int S, int S0) {
if((S & S0) || (S & (S0 >> 1) || (S0 << 1) & S)) return 0;
return 1;
}
namespace DP {
void init() {
Init();
}
void dp() {
f[0][1][0] = 1;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= cnt; j++) {
for(int k = 0; k <= K; k++) {
if(sum[j] <= k) {
for(int p = 1; p <= cnt; p++) {
if(chk(s[j], s[p]))
f[i][j][k] += f[i - 1][p][k - sum[j]];
}
}
}
}
}
}
}
signed main() {
read(n), read(K);
DP::init();
DP::dp();
LL ans = 0;
for(int i = 1; i <= cnt; i++) {
ans += f[n][i][K];
}
printf("%lld\n", ans);
return 0;
}