题目大意:
在
n
×
n
n×n
n×n的棋盘里面放
K
K
K个国王,使他们互不攻击,共有多少种摆放方案。
国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
1
<
=
N
<
=
9
1 <=N <=9
1<=N<=9
0
<
=
K
<
=
N
∗
N
0 <= K <= N * N
0<=K<=N∗N
分析:
发现
n
n
n很小,可以考虑状压,
我们可以先处理出对于一个
n
∗
1
n*1
n∗1的矩阵能选的合法位置状态有什么,
即
A
1
,
A
2
,
.
.
.
,
A
t
o
t
−
1
,
A
t
o
t
A_1,A_2,...,A_{tot-1},A_{tot}
A1,A2,...,Atot−1,Atot,
同时记录他们这个状态内有多少个位置被选
即
B
1
,
B
2
,
.
.
.
,
B
t
o
t
−
1
,
B
t
o
t
B_1,B_2,...,B_{tot-1},B_{tot}
B1,B2,...,Btot−1,Btot
然后我们可以设
d
p
i
,
j
,
k
dp_{i,j,k}
dpi,j,k表示前
i
i
i行,第
i
i
i选的状态是
A
j
A_j
Aj,总共选了
k
k
k个国王的合法方案总数
初值:
d
p
1
,
i
,
B
i
=
1
dp_{1,i,B_i}=1
dp1,i,Bi=1
每次枚举上一行的一个状态
A
l
A_l
Al,
当
A
j
,
A
l
A_j,A_l
Aj,Al不冲突的时候,则可以转移:
d
p
i
,
j
,
k
=
d
p
i
,
j
,
k
+
d
p
i
−
1
,
l
,
k
−
B
j
dp_{i,j,k}=dp_{i,j,k}+dp_{i-1,l,k-B_{j}}
dpi,j,k=dpi,j,k+dpi−1,l,k−Bj
最后的
A
n
s
w
e
r
Answer
Answer即为
∑
i
=
1
t
o
t
d
p
n
,
i
,
K
\sum_{i=1}^{tot}dp_{n,i,K}
∑i=1totdpn,i,K
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <algorithm>
#define N 10
using namespace std;
typedef long long ll;
struct Node { int Num, Wxy; }A[1<<N];
ll dp[N][1<<N][1<<N];
int n, K, tot;
void Find_All(int dep, int num, int cdp)
{
if (dep == n)
{
A[++tot].Num = num, A[tot].Wxy = cdp;
return;
}
Find_All(dep + 1, num, cdp);
if (!((num >> (dep - 1)) & 1)) Find_All(dep + 1, (num | (1 << dep)), cdp + 1);
}
int main()
{
scanf("%d %d", &n, &K);
Find_All(0, 0, 0);
for (int i = 1; i <= tot; i++) dp[1][i][A[i].Wxy] = 1;
for (int i = 2; i <= n; i++)
for (int j = 1; j <= tot; j++)
for (int k = A[j].Wxy; k <= K; k++)
for (int l = 1; l <= tot; l++)
if ((!((A[j].Num << 1) & A[l].Num)) && (!((A[j].Num >> 1) & A[l].Num)) && (!(A[j].Num & A[l].Num)))
dp[i][j][k] = dp[i][j][k] + dp[i - 1][l][k - A[j].Wxy];
ll Answer = 0;
for (int i = 1; i <= tot; i++) Answer = Answer + dp[n][i][K];
printf("%lld\n", Answer);
return 0;
}