[Bzoj1087][SCOI2005]互不侵犯King(状压dp)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1087

还不错的状态压缩题目,把国王的位置看成1,其余位置看成0,则n行每行的可能出现的状态为1<<n,如果同时考虑n行的状态就为1<<(n*n),必不可能。

所以先预处理出每行所有的合法状态,及没有相邻的1出现,并处理出每个状态的1的个数。

定义状态dp[i][j][k]表示1-i行中第i行为j状态,1-i行中有k个国王时的方案数。

则转移为$dp[i][j][k]=\sum dp[i-1][{j}'][{k}'],{j}'和{k}'$为可以转移的合法状态。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 ll dp[15][1100][110];
 5 ll st[1100], kth[1100];
 6 int main() {
 7     int n, k;
 8     scanf("%d%d", &n, &k);
 9         int len = 0;
10         for (int i = 0; i < (1 << n); i++) {
11             if (!((i << 1)&i)) {
12                 st[++len] = i;
13                 kth[len] = 0;
14                 int w = i;
15                 while (w) {
16                     kth[len] += w % 2;
17                     w /= 2;
18                 }
19             }
20         }
21         for (int i = 1; i <= len; i++) {
22             if (kth[i] <= k)
23                 dp[1][i][kth[i]] = 1;
24         }
25         for (int i = 2; i <= n; i++) {
26             for (int j = 1; j <= len; j++) {
27                 for (int p = 1; p <= len; p++) {
28                     if ((st[j] & st[p]))
29                         continue;
30                     if ((st[j] & (st[p] << 1)))
31                         continue;
32                     if (((st[j] << 1) & st[p]))
33                         continue;
34                     for (int kk = 1; kk <= k; kk++) {
35                         if (kth[j] + kk <= k) {
36                             dp[i][j][kth[j] + kk] += dp[i - 1][p][kk];
37                         }
38                     }
39 
40                 }
41             }
42         }
43         ll ans = 0;
44         for (int i = 1; i <= n; i++) {
45             for (int j = 1; j <= len; j++) {
46                 ans += dp[i][j][k];
47             }
48         }
49         printf("%lld\n", ans);
50         return 0;
51 }

 

posted @ 2019-07-02 08:38  祈梦生  阅读(158)  评论(0编辑  收藏  举报