码迷,mamicode.com
首页 > 其他好文 > 详细

15.蒙德里安的梦想 状态压缩DP

时间:2020-07-05 13:26:10      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:inf   判断   typedef   turn   ace   sizeof   cin   amp   com   

技术图片

 技术图片

位运算 + 二进制表示状态 = 状态压缩DP

 先把横着的小方块放好,然后剩下位置用竖着的小方块填充

技术图片

 然后就转化为求横着摆放小方块的方案数

按列来求

状态表示:

技术图片

 dp[i][j]表示所有摆到了第i列,然后上一列伸出来的小方块的状态是j的情况下,总的方案数

状态转移:
枚举一下i - 1列的状态

比如说当前状态i是j = 00001

然后上一个状态i - 1是k = 10010

从i - 1列伸到第i列的:j = 00001

从i - 2列伸到第i - 1列的:k = 10010

位运算的预备知识

与运算    &

或运算    |  

技术图片

条件一:不能有冲突。

  也就是需要判断(j & k)== 0,若等于0,表示没有冲突

条件二:第i - 1列空余格子一定是连续的,且是偶数,因为要竖着放小方块

  j | k里面,所有0的位置,就是第i - 1列所有空白的格子

  就是j | k里面不能存在连续奇数个0

只要满足这两个条件,就可以转移过来

技术图片

 把所有满足条件的k加起来,就是状态转移方程

状态数量:11 * 2 ^ 11 

转移数量:2 ^ 11

时间复杂度: 11 * 2 ^ 11 * 2 ^ 11 = 4 * 10 ^ 7

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N = 13, M = 1 << N;
 5 ll dp[N][M];
 6 bool st[M];
 7 int main() {
 8     int n, m;
 9     while (cin >> n >> m && n != 0) {
10         //预处理一下,所有的状态是否不存在连续奇数个0
11         for (int i = 0; i < (1 << n); i++) { //遍历所有的状态
12             st[i] = true; //假设是成立的
13             int cnt = 0; //cnt是当前这一段连续0的个数
14             for (int j = 0; j < n; j++) { //n是这个二进制数的位数
15                 if (i >> j & 1) { //如果当前这一位是1,说明上一段已经截止了
16                     if (cnt & 1) { //判断上一段连续的0是否是奇数个,若是
17                         st[i] = false; //说明第i个状态时不合法的,存在了连续奇数个0
18                     }
19                     cnt = 0; //遇到1以后,连续奇数个0已经结束了,新开始一段
20                 } else {
21                     cnt++;
22                 }
23             }
24             if (cnt & 1) { //然后判断最后一段0的个数
25                 st[i] = false;
26             }
27         }
28         //然后是dp的过程
29         memset(dp, 0, sizeof dp); //把dp数组置为0
30         dp[0][0] = 1; //边界情况
31         for (int i = 1; i <= m; i++) { //枚举所有的列
32             for (int j = 0; j < (1 << n); j++) { //枚举第i列的所有状态
33                 for (int k = 0; k < (1 << n); k++) { //再枚举第i - 1列的所有状态
34                     if ((j & k) == 0 && st[j | k]) {
35                         dp[i][j] += dp[i - 1][k];
36                     }
37                 }
38             }
39         }
40         cout << dp[m][0] << endl; //答案
41     }
42     return 0;
43 }

 

15.蒙德里安的梦想 状态压缩DP

标签:inf   判断   typedef   turn   ace   sizeof   cin   amp   com   

原文地址:https://www.cnblogs.com/fx1998/p/13245772.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!