洛谷P1896 互不侵犯

又是一道状压DP求方案数的题...

多了一个放k个的限制,于是我们把数组多开一维。

f[i][j][k]表示前i行放了j个,第i行状态为k的方案数。

然后老套路DFS转移,这次要多记录一个cnt表示上一行的棋子数。

然后因为什么都不放也是可以转移的,所以我们输出f[m + 1][k][0]即为最终答案。

中间有个num数组是指这个状态有多少个棋子。

 1 #include <cstdio>
 2 
 3 typedef long long LL;
 4 const int N = 10;
 5 
 6 LL f[N + 1][82][1 << N], ans;
 7 int pre, m, num[1 << N], cnt, k;
 8 
 9 inline int check(int s) {
10     int a = 0;
11     while(s) {
12         a += s & 1;
13         s >>= 1;
14     }
15     return a;
16 }
17 
18 void DFS(int x, int y, int ns) {
19     if(y >= m) {
20         f[x][cnt + num[ns]][ns] += ans;
21         return;
22     }
23     DFS(x, y + 1, ns);
24     if(!y) {
25         if(!((pre >> y) & 1) && !((pre >> (y + 1)) & 1) && cnt + num[ns] < k) {
26             DFS(x, y + 1, ns | 1);
27         }
28         return;
29     }
30     if(!((ns >> (y - 1)) & 1) && !((pre >> (y - 1)) & 1) && !((pre >> y) & 1) && !((pre >> (y + 1)) & 1) && cnt + num[ns] < k) {
31         DFS(x, y + 1, ns | (1 << y));
32     }
33     return;
34 }
35 
36 int main() {
37     scanf("%d%d", &m, &k);
38     int lm = 1 << m;
39     for(int i = 0; i < lm; i++)  {
40         num[i] = check(i);
41     }
42     f[0][0][0] = 1;
43     for(int i = 1; i <= m + 1; i++) {
44         for(int j = 0; j < lm; j++) {
45             for(int p = 0; p <= k; p++) {
46                 if(!f[i - 1][p][j]) {
47                     continue;
48                 }
49                 ans = f[i - 1][p][j];
50                 pre = j;
51                 cnt = p;
52                 DFS(i, 0, 0);
53             }
54         }
55     }
56 
57     printf("%lld", f[m + 1][k][0]);
58     return 0;
59 }
AC代码

 

posted @ 2018-09-30 09:13  garage  阅读(101)  评论(0编辑  收藏  举报