题目传送门
1 /*
2 题意:n*n的矩阵,放置k个king,要求king互相不能攻击,即一个king的8个方向都没有另外的king,求方案个数
3 状态压缩DP:dp[i][num[j]][s] 代表在第i行,放置num[j]个king,其状态为s时的方案数
4 首先对state进行筛选,即一行king左右相邻没有另外的king,确定tot
5 接着对第一行进行处理,对2~n行DP递推,同样要满足各种条件限制,num个数和不超过k,s1,s2状态也要ok
6 最后累加放置k个king时的方案数
7 详细解释:http://blog.csdn.net/roney_win/article/details/9617081
8 */
9 #include <cstdio>
10 #include <iostream>
11 #include <algorithm>
12 #include <cstring>
13 #include <cmath>
14 #include <map>
15 #include <set>
16 #include <string>
17 using namespace std;
18
19 const int MAXN = 15;
20 const int INF = 0x3f3f3f3f;
21 long long dp[15][110][150];
22 int st[150];
23 int num[150];
24
25 bool ok(int x)
26 {
27 if ((x & (x << 1)) == 0) return true;
28 else return false;
29 }
30
31 int init_state(int n, int k)
32 {
33 int tot = 1 << n;
34 int cnt = 0;
35 for (int i=0; i<tot; ++i)
36 {
37 if (ok (i))
38 {
39 num[cnt] = 0;
40 int t = i;
41 while (t)
42 {
43 num[cnt] += (t & 1);
44 t >>= 1;
45 }
46 st[cnt++] = i;
47 }
48 }
49
50 return cnt;
51 }
52
53 int main(void) //SGU 223 Little Kings
54 {
55 #ifndef ONLINE_JUDGE
56 freopen ("E.in", "r", stdin);
57 #endif
58
59 int n, k;
60 while (~scanf ("%d%d", &n, &k))
61 {
62 int tot = init_state (n, k);
63 memset (dp, 0, sizeof (dp));
64
65 for (int s=0; s<tot; ++s)
66 {
67 if (num[s] <= k)
68 {
69 dp[1][num[s]][s]++;
70 }
71 }
72
73 for (int i=1; i<=n-1; ++i)
74 {
75 for (int j=0; j<=k; ++j)
76 {
77 for (int s1=0; s1<tot; ++s1)
78 {
79 if (num[s1] <= j)
80 {
81 int res = j - num[s1];
82 for (int s2=0; s2<tot; ++s2)
83 {
84 if (num[s2] <= res)
85 {
86 if ((st[s1] & st[s2]) == 0)
87 {
88 if (((st[s1] & (st[s2] << 1)) == 0) && ((st[s1] & (st[s2] >> 1)) == 0))
89 {
90 dp[i+1][j][s1] += dp[i][res][s2];
91 }
92 }
93 }
94 }
95 }
96 }
97 }
98 }
99
100 long long ans = 0;
101 for (int s=0; s<tot; ++s)
102 {
103 if (num[s] <= k)
104 {
105 ans += dp[n][k][s];
106 }
107 }
108
109 printf ("%I64d
", ans);
110
111 }
112
113 return 0;
114 }
115
116
117 /*
118 Test #1
119 */