题目:

给你\(n*m(1<=n,m<=11)\)的方格矩阵,要求用1*2的多米诺骨牌去填充,问有多少种填充方法。

比如下图是对于如下2x6的方格矩阵,可能的填充方案之一。

该如何使用动态规划的方式解决这道题呢?先了解一下状态压缩算法。

状态压缩通常是使用一个整数来表示一个集合,比如整数3,二进制表示为11,第一位状态为1,第二位状态为1,数字2的二进制表示为10,第一位的状态为1,第二位的状态为0,数字1的二进制表示为01,第一位为0,第二位为1,数字0的二进制可以表示为00,两位的状态都是0。

这就是说,状态可以保存在一个整数里面,对于状态压缩DP,其实也是用状态压缩后的整数表示一个维度,然后进行状态转移。

状态压缩DP:采用状态压缩算法的DP问题,也就是用整数表示集合,然后将该整数作为DP的一个维度来进行DP状态转移。

继续看题,其实这道题的解法并不简单,甚至于有些晦涩,光是理解状态压缩DP并不一定能够看懂源代码。

首先定义状态转移方程:

\(f(i, j) = f(i-1, k)\)之和,\(j, k\)属于\([0,1<<m)\)

且满足 \(j\&k==0\)

满足 $ j | k$是有连续个0的状态

f(i,j)表示第i行的状态为j时,前i行的方案总数。且定义状态1表示竖着的上面一部分,其他状态为0。

对于约束的理解是本题的关键,

约束1:j&k == 0 是因为不可能上下都是1。

约束2:j|k合并后状态0必须是连续偶数个,这个可以预先缓存起来,不用每次都算。详见代码注释。

源代码:

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <bitset>
#include <iostream>
#include <set>
#include <string>
#include <vector> using namespace std; long long f[12][1 << 11];
int in_s[1 << 11]; // 注意这里一定要用64位的整数
long long solve(int n, int m) {
for (int i = 0; i < 1 << m; ++i) {
int cnt = 0, has_odd = 0;
// 遍历m中的每一位
for (int j = 0; j < m; ++j) {
if (i >> j & 1) {
//把cnt的值先存放到has_odd上,然后清零
has_odd |= cnt, cnt = 0;
} else {
//如果是偶数个0,则肯定cnt最后为0,因为0^1=1 1^1=0
cnt ^= 1;
}
}
// 如果cnt=1则表明存在连续的奇数个0位
in_s[i] = has_odd | cnt ? 0 : 1;
} f[0][0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < 1 << m; ++j) {
f[i][j] = 0;
for (int k = 0; k < 1 << m; ++k) {
// 上面是1下面必须是0
// 0必须是连续偶数个
if ((j & k) == 0 && in_s[j | k]) {
// 满足要求后加上i-1行k的所有情况
f[i][j] += f[i - 1][k];
}
}
}
} // 最后一行的j所有位都是0
return f[n][0];
} int main() {
#ifdef __MSYS__
freopen("test.txt", "r", stdin);
#endif int n, m; while (cin >> n >> m && n) {
cout << solve(n, m) << endl;
}
return 0;
}

骨牌摆放问题 POJ 2411(状态压缩DP)的更多相关文章

  1. Mondriaan's Dream(POJ 2411状态压缩dp)

    题意:用1*2的方格填充m*n的方格不能重叠,问有多少种填充方法 分析:dp[i][j]表示i行状态为j时的方案数,对于j,0表示该列竖放(影响下一行的该列),1表示横放成功(影响下一列)或上一列竖放 ...

  2. poj 2411 状态压缩dp

    思路:将每一行看做一个二进制位,那么所有的合法状态为相邻为1的个数一定要为偶数个.这样就可以先把所有的合法状态找到.由于没一层的合法状态都是一样的,那么可以用一个数组保存.由第i-1行到第i行的状态转 ...

  3. POJ 1185 状态压缩DP(转)

    1. 为何状态压缩: 棋盘规模为n*m,且m≤10,如果用一个int表示一行上棋子的状态,足以表示m≤10所要求的范围.故想到用int s[num].至于开多大的数组,可以自己用DFS搜索试试看:也可 ...

  4. POJ 1185 状态压缩DP 炮兵阵地

    题目直达车:   POJ 1185 炮兵阵地 分析: 列( <=10 )的数据比较小, 一般会想到状压DP. Ⅰ.如果一行10全个‘P’,满足题意的状态不超过60种(可手动枚举). Ⅱ.用DFS ...

  5. POJ 2411 状态压缩递,覆盖方案数

    无非就是横着放与竖着放,状态中用1表示覆盖,0表示未覆盖. #include <iostream> #include <vector> #include <algorit ...

  6. poj 2923(状态压缩dp)

    题意:就是给了你一些货物的重量,然后给了两辆车一次的载重,让你求出最少的运输次数. 分析:首先要从一辆车入手,搜出所有的一次能够运的所有状态,然后把两辆车的状态进行合并,最后就是解决了,有两种方法: ...

  7. poj 2688 状态压缩dp解tsp

    题意: 裸的tsp. 分析: 用bfs求出随意两点之间的距离后能够暴搜也能够用next_permutation水,但效率肯定不如状压dp.dp[s][u]表示从0出发訪问过s集合中的点.眼下在点u走过 ...

  8. poj 3254 状态压缩DP

    思路:把每行的数当做是一个二进制串,0不变,1变或不变,找出所有的合法二进制形式表示的整数,即相邻不同为1,那么第i-1行与第i行的状态转移方程为dp[i][j]+=dp[i-1][k]: 这个方程得 ...

  9. POJ 3254 状态压缩 DP

    B - Corn Fields Crawling in process... Crawling failed Time Limit:2000MS     Memory Limit:65536KB    ...

  10. POJ 1321 棋盘问题(状态压缩DP)

    不总结的话, 同一个地方会 WA 到死 思路: 状态压缩 DP. 1. s 表示压缩状态, 若第 i 列放了棋子, 那么该列置 1, 否则该列置 0. 假如 s = 3(0x011) 那么表示棋盘的第 ...

随机推荐

  1. 【Javaweb】JavaEE项目的三层架构 | 快速搭建

    逻辑类图 分层的目的是为了解耦.解耦就是为了降低代码的耦合度.方便项目后期的维护和升级. 不同的层有不同的包 web层 com.stguigu.web/servlet/controller servi ...

  2. PageHelper插件注意事项

    PageHelper插件注意事项 使用PageHelper.startPage后要紧跟查询语句 下面的代码就有可能出问题: PageHelper.startPage(10, 10); if(param ...

  3. KNN算法之KD树(K-dimension Tree)实现 K近邻查询

    KD树是一种分割k维数据空间的数据结构,主要应用于多维空间关键数据的搜索,如范围搜索和最近邻搜索. KD树使用了分治的思想,对比二叉搜索树(BST),KD树解决的是多维空间内的最近点(K近点)问题.( ...

  4. ES集群搭建和Kibana管理集群

    搭建实例 先复制2份解压后的完整目录,将里面的data和log删除. elasticsearch-6.8.23-node2 elasticsearch-6.8.23-node3 修改3个实例的配置文件 ...

  5. 华企盾DSC导致导出文件报错常见处理方法

    1.导出文件的进程和打开该文件的进程启用OLE控制是否都是未勾选,以及启用虚拟重定向是否设置一致(要么都勾选要么都不勾) 2.用procmon监控个人模式下导出非加密的文件,搜索writefile的进 ...

  6. 2023"安洵杯"第六届网络安全挑战赛-Misc WP

    dacongのsecret 题目 我的解答: 题目给出一张png图片和一个加密压缩包,压缩包里面还存在另一张jpg图片 看名字就知道是盲水印.由于压缩包里的图片提不出来,因此是单图盲水印,我们使用工具 ...

  7. Typora远程代码执行漏洞 - CVE-2023-2317

    Typora - CVE-2023-2317 简介 Typora一个常用的markdown编辑器,在1.6.7之前存在XSS漏洞,可以通过传入参数触发来加载恶意的JavaScript代码 分析 在ty ...

  8. Python——第一章:if语法规则

    if语句的语法规则: ======第一种======        if 条件:            代码        如果条件成立就执行代码        如果不成立, 就不执行 案例1: mo ...

  9. BUUCTF Reverse 新年快乐

    下载文件先查壳,可以看到有UPX壳 用upx脱壳 拖到ida pro32,shift+F12查看字符串,看到关键字flag,双击进去 双击然后f5查看伪代码 main函数伪代码 关键函数: strnc ...

  10. 第十三部分_awk

    一.awk介绍 1. awk概述 awk是一种编程语言,主要用于在linux/unix下对文本和数据进行处理,是linux/unix下的一个工具.数据可以来自标准输入.一个或多个文件,或其它命令的输出 ...