193、【动态规划】AcWing —— 291. 蒙德里安的梦想:状压dp详细解析(C++版本)

news2025/7/10 22:58:16

题目描述

在这里插入图片描述
在这里插入图片描述
原题链接:291. 蒙德里安的梦想

解题思路

(1)状态压缩dp先导知识

在这里插入图片描述
状态压缩会用二进制位来存储状态信息,在状态计算时,将整数转化为二进制爹形式进行计算。
在这里插入图片描述
在这里插入图片描述
可表示的状态就是 2 n 2^n 2n 个。

(2)题目分析

因为已经规定长方体的规格为1×2,摆放方式只有横着摆放和竖着摆放两种。我们可以先让长方体横着摆放,剩余空余位置竖着摆放,然后看哪些位置摆放情况可以让竖着摆放的长方体填满整个方框即可。

因此,本问题就转化为了,找到合法的横着摆放长方体的情况总数
在这里插入图片描述
此时规定,当第j列、第i行为1时,代表从当前位置横着新摆放一个长方体(此时第j+1列、第i行,会由第i列伸出一个长方体)。而当第i列、第j行为0时,代表当前位置没有横着新摆放一个长方体。

因此,对于合法摆放位置的规定:
(1)第j -1列和第j列没有的长方体没有出现重叠
在这里插入图片描述
此时由于第j-1列新横放的方块和第j列新横放的方块出现重叠,因此此状态不合法。

(2)第j列的空格数为偶数个
在这里插入图片描述
此时第j列的空格数不为偶数个,而是奇数个,就会导致1×2的长方体一定不能填充满这一列,因此此状体不合法。

根据上述的讨论情况,就确定了这样子的dp解法。
在这里插入图片描述

  • 动态规划五步曲:

(1)dp[i][j]含义: 第i列处,状态为j时,合法的方案数。

(2)递推公式: f [ i , j ] = ∑ 0 2 n − 1 f [ i − 1 , k ] f[i, j] = \sum_0^{2^n-1} f[i - 1, k] f[i,j]=02n1f[i1,k],表示从第i-1列到达第i列,可转化为状态j的所有合法状态求和。

(3)dp数组初始化: dp[0][0] = 1,代表第0列不横着放,此时有且仅有一种方案。

(4)遍历顺序: 从左到右,从上到下。

(5)举例:
在这里插入图片描述

(3)详细代码

#include <iostream>
#include <cstring>

using namespace std;

const int N = 12, M = 1 << N;
long long  dp[N][M];		// 数据量大,采用long long
bool state[M];              // 用于记录该状态是否合法(有偶数个0则合法)
int n, m;

int main() {
    // 输入行列,若有一个为0,则退出
    while(cin >> n >> m, n || m) {
        // 1、预处理:根据列值化成二进制值,预先判定合法的横着摆放位置,每次枚举所有行,枚举完所有的合法状态
        for(int i = 0; i < 1 << n; i++) {       // 1 << n:对n进行二进制化,相当于是化成了2^n,让i从0遍历到2^n-1,查询各个状态
            state[i] = true;                    // 先假设当前摆放情况合法
            int cnt = 0;                        // 记录当前状态下有多少个连续的0(若有奇数个0,则这几个空位置无法用竖着的长方体填满,不合法)
            for(int j = 0; j < n; j++) {        // j从0~n,用于依次对当前的i进行移位,来获取最后一位的信息进行一些判定
                if(i >> j & 1) {                // i >> j:将i左移位j位,判定左移后最后一位是否为1(若为1说明该处新横放有长方体)
                    if(cnt & 1) {               // 再判定摆放长方体之前的位置是否为奇数个0,若为奇数个0,则不合法,标记状态后跳出
                        state[i] = false;
                        break;
                    }
                } else {                        // 若左移后最后一位不为1,则说明当前位置没有横着新放长方体
                    cnt++;
                }
            }
            if(cnt & 1)         state[i] = false;   // 判定到达最后一个位置时是否合法,也为偶数个0(因为在做上面最后一次for循环时,可能会cnt++后变为奇数)
        }
        
        // 2、dp数组初始化
        memset(dp, 0, sizeof dp);                   // 初始化dp为0
        dp[0][0] = 1;                               // dp[0][0]:第0列,状态为0时,表明没有一个横着放长方体,此时有且仅有一种情况。
        
        // 3、进行状态计算
        for(int i = 1; i <= m; i++) {                       // 按列进行遍历,枚举完所有列
            for(int j = 0; j < 1 << n; j++) {               // 枚举第i列的状态j
                for(int k = 0; k < 1 << n; k++) {           // 枚举第i-1列的状态k
                	// 判定第i-1列的状态k能否转移到第i列的状态j:
                    // (j & k) == 0:判定第i列和i-1列是否无重叠,无重叠则合法返回true,有重叠则不合法返回false
                    // state[j | k] : 其中 j | k 相当于是进行异或后让第i-1列新摆放的长方体和第i列新摆放的长方体都出现,看剩余位置能否由竖着摆放的长方体填满
                    if((j & k) == 0 && state[j | k]) {      
                        dp[i][j] += dp[i - 1][k];           // 满足转移条件,则当前的状态情况加上由dp[i-1][k]转化来的情况
                    }
                }
            }
        }
        
        cout << dp[m][0] << endl;               // 在摆放位置为0~m-1,合法的第m列应该是从m-1列没有方块伸出到第m列
    }
    
    
    return 0;
}

问题一:为什么dp遍历时,先遍历j后遍历k可表示先遍历第i列,再遍历第i-1列的状态?

答:因为我们要求的是从第i-1列转化到第i列是的所有合法状态,因此先for循环j时,代表我们的目标列i此时的状态为j再for循环k里表示从0-2^n-1的各个合法状态,此时从逻辑上 就相当于从第i-1列到第i列的所有的状态匹配情况,当匹配到合法状态时,就进行状态计算。

问题二:为什么遍历pd时,i从1开始?
因为在里面计算状态计算时,默认会是i-1和i进行比较,因此最外for从i开始。

参考视频:9.93 蒙德里安的梦想 状态压缩DP——信息学竞赛培训课程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/396257.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python 列表删除多个元素

文章目录一. 删除列表多个元素方法1 使用枚举&#xff1a;2. 使用python中List.pop()方法3. 使用python中List.remove()方法4. 注意二. 使用双指针法删除列表多个元素1. 问题描述&#xff1a;2. 解决方法&#xff1a;3. 代码如下&#xff1a;三. 总结四. 相关链接一. 删除列表多…

扩盘操作LVM扩容操作-Centos7

生产环境要扩容&#xff0c;太久没试过LVM&#xff0c;记录一下走过的坑 [rootarchive ~]# df -h #查看磁盘挂载&#xff0c;对/dev/mapper/vgnfs-lvdata进行扩容 文件系统 容量 已用 可用 已用% 挂载点 devtmpfs 909M 0 909M 0…

文件上传漏洞知识总结

直接使用别人的靶场总感觉不太好&#xff0c;那么就干脆自己写一个自己的文件上传靶场吧。正好博客之前也没有单独总结过文件上传的知识点&#xff0c;那么就顺便水一篇文章&#xff0c;岂不是一举两得。当然关于文件上传 upload-labs 总结的比较全面了&#xff0c;非强迫症患者…

HTTP协议详解(上)

目录 前言&#xff1a; 认识URL HTTP协议方法 通过Fiddler抓包 GET和POST之间典型区别 header详解 HTTP响应状态码 常见状态码解释 状态码分类 HTTP协议报文格式 小结&#xff1a; 前言&#xff1a; HTTP协议属于应用层协议&#xff0c;称为超文本传输协议&#xff…

aws dynamodb 基础概念和理论

参考资料 https://amazon-dynamodb-labs.workshop.aws/https://docs.amazonaws.cn/amazondynamodb/latest/developerguide/Introduction.html dynamodb的工作原理 核心概念 table、item和attributes是dynamodb的核心组件&#xff0c;可以分别对应关系型数据库中的表&#x…

JavaScript新手学习手册-基础代码(三)

与上篇博客相接 一&#xff1a;Date对象 var date new Date();console.log(date); //全部时间console.log(date.getFullYear()); //年console.log(date.getMonth()); //月console.log(date.getDay()); //星期几console.log(date.getHours()) //时console.log(d…

java实现Hbase 增删改查

目录 一、新建一个maven工程 二、代码实现 2.1、配置hbase信息&#xff0c;连接hbase数据库 2.2、创建命名空间 2.3、创建表 2.4、删除表&#xff0c;删除之前要设置为禁用状态 2.5、添加数据 2.6、获取命令表空间 / tables列表 2.7、get方法查看表的内容 2.8、scan方法…

腾势D9改装来了,帮大家总结了一些需要改装的项目

最近腾势D9真的太火了&#xff0c;不仅外观霸气&#xff0c;内饰也是非常豪华。 1月份销量在MPV里已经排名第二了&#xff0c;性价比很高。 这边整理了一些改装项目供大家参考&#xff0c;有什么想法可以评论区一起讨论哦1. 电吸门 有车主吐槽车门难关&#xff0c;由于车内空间…

计算机网络:ICMP协议

网际控制报文协议ICMP ICMP协议支持主机或者路由器差错报告和网络探询 类型表明ICMP报文是哪类检验和&#xff1a;检验整个ICMP报文ICMP报文可分为ICMP差错报文和ICMP询问报文。 ICMP差错报告报文 终点不可达&#xff1a;当路由器或者主机不能交付数据报时&#xff0c;向源站…

Spring - Spring框架概述面试题总结

文章目录01. 什么是Spring&#xff1f;02. Spring框架的设计目标&#xff0c;设计理念&#xff0c;和核心是什么&#xff1f;03. Spring的优点是什么&#xff1f;04. Spring框架中都用到了哪些设计模式&#xff1f;05. Spring有哪些应用场景?06. Spring由哪些模块组成&#xf…

基于DDD的微服务落地

DDD四层架构对实时性要求高的强一致性业务场景&#xff0c;可采取分布式事务。分布式事务有性能代价&#xff0c;在设计时需要平衡考虑业务拆分、数据一致性、性能和实现的复杂度&#xff0c;尽量避免分布式事务的产生。领域事件驱动的异步方式是分布式架构常用的设计方式&…

【python】使用python将360个文件夹里的照片,全部复制到指定的文件夹中,并且按照顺序重新命名

最近要做一个图像生成的课题&#xff0c;在网上找了一个混合的数据集。这个数据集中一共有360个文件夹&#xff0c;然后文件夹中有6-9张不等的照片&#xff0c;我的目标就是编写python代码将所有的照片取出来&#xff0c;放到一个指定的文件夹里&#xff0c;并且从1开始按照顺序…

yolov8行人识别教程(2023年毕业设计+源码)

yolov8识别视频直接上YOLOv8的结构图吧&#xff0c;小伙伴们可以直接和YOLOv5进行对比&#xff0c;看看能找到或者猜到有什么不同的地方&#xff1f; Backbone&#xff1a;使用的依旧是CSP的思想&#xff0c;不过YOLOv5中的C3模块被替换成了C2f模块&#xff0c;实现了进一步的轻…

VMware虚拟机安装Ubuntu 2022最新版详细图文安装教程(VMware虚拟机安装+Ubuntu下载+VMware虚拟机配置运行)

名人说:君子生非异也,善假于物也。——荀子 Code_流苏(CSDN) o(‐^▽^‐)o很高兴你打开了这篇博客,跟着步骤一步步尝试安装吧。✧ 目录 一、简单介绍二、安装虚拟机VMware三、Ubuntu镜像下载四、虚拟机VMware配置及运行★如有疑问,欢迎评论,博主看到即回!当然,期待你的…

【基础算法】双指针---判断子序列

&#x1f339;作者:云小逸 &#x1f4dd;个人主页:云小逸的主页 &#x1f4dd;Github:云小逸的Github &#x1f91f;motto:要敢于一个人默默的面对自己&#xff0c;强大自己才是核心。不要等到什么都没有了&#xff0c;才下定决心去做。种一颗树&#xff0c;最好的时间是十年前…

极速开发,无限可能,2023网易低代码大赛全新赛季启动

去年火爆的低代码大赛还犹在目&#xff0c;近800人用轻舟低代码平台畅享开发乐趣。这不&#xff0c;2023网易低代码大赛即刻启动&#xff0c;3月6日至3月27日限时开放报名&#xff0c;全新角逐&#xff0c;正式展开&#xff01;1\ 获胜者可得万元大奖、猪厂工作机会 /Low Code …

JavaEE课程实践-Servlet的部署(tomcat服务器)

目录 Servlet简述 tomcat服务器的安装和运行 Servlet的部署 部署具体步骤 一、创建maven工程 二、创建Servlet类 三、导入相应jar包 四、编写Servlet代码 五、运行maven项目&#xff0c;启动tomcat服务器 六、测试访问是否成功。 Servlet简述 Servlet 是 Java EE 技术…

第六章:多线程

第六章&#xff1a;多线程 6.1&#xff1a;程序、进程、线程基本概念 程序 程序program是为了完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码&#xff0c;静态对象。 进程 ​ 进程process是程序的一次执行过程&#xff0c;或是正在运行的一个程序。是一个…

vue3相比vue2性能上提升体现

vue3相比vue2&#xff0c;在 编译阶段&#xff0c;源码体积 响应式系统 都做了性能提升不以解决实际业务痛点的更新都是耍流氓1. ts的支持2. 移除了不常用的api,例如 过滤器 $on $off $once 实例方法 内联模板attribute $destroy3. 加了tree - shaking4. 移除了mixin缺点&#…

ESP32设备驱动-RFID-RC522模块驱动

RFID-RC522模块驱动 文章目录 RFID-RC522模块驱动1、RFID-RC522介绍2、硬件准备3、软件准备4、驱动实现1、RFID-RC522介绍 基于 NXP 的 MFRC522 IC 的 RC522 RFID 模块通常带有一个 RFID 卡标签和具有 1KB 内存的密钥卡标签。 最重要的是,它可以写一个标签,这样你就可以在里…