状态压缩、记忆化搜索---蒙德里安的梦想

291. 蒙德里安的梦想 - AcWing题库

求把 N×MN×M 的棋盘分割成若干个 1×21×2 的长方形,有多少种方案。

例如当 N=2,M=4N=2,M=4 时,共有 55 种方案。当 N=2,M=3N=2,M=3 时,共有 33 种方案。

如下图所示:

2411_1.jpg

输入格式

输入包含多组测试用例。

每组测试用例占一行,包含两个整数 NN 和 MM。

当输入用例 N=0,M=0N=0,M=0 时,表示输入终止,且该用例无需处理。

输出格式

每个测试用例输出一个结果,每个结果占一行。

数据范围

1≤N,M≤111≤N,M≤11

输入样例:

解释

1 2 
1 3 
1 4 
2 2 
2 3 
2 4 
2 11 
4 11 
0 0
输出样例:

解释

1 
0 
1 
2 
3 
5 
144 
51205

这道题的本质是将棋盘分割成若干个1×2的长方形。通过状态压缩的思想,我们将棋盘的每一列进行压缩,用位运算表示每一列的状态,然后通过动态规划(DP)来实现转移。

题目分析

  • 棋盘的状态压缩:由于棋盘是二维的,我们需要解决的是如何摆放这些1×2的长方形。在每列上我们可以通过一个二进制数表示列的状态。每一位(bit)代表这一列中的每一个格子,当这一位为1时表示该格子已被占用,为0表示未被占用。

  • 列与列之间的状态转移:由于每一列的状态与相邻列的状态有关,因此需要考虑相邻列之间的“兼容性”,也就是确保相邻的列不会发生重叠。例如,当前列与前一列不能有相邻的空格被两个不同的长方形占据,否则就不合法。

状态压缩的应用

  1. 状态表示

    • 使用一个 n 位的二进制数 i 来表示一列中的每个格子的状态。比如,对于一个 2×4 的棋盘,可以使用 2 位二进制数表示每一列的状态:

      • 00 表示这一列的两个格子都没有被占据;

      • 01 表示这一列的上面格子已经被占据,下面的格子没有被占据;

      • 10 表示这一列的上面格子没有被占据,下面的格子被占据;

      • 11 表示这一列的两个格子都已经被占据。

  2. 合法状态的判断

    • 每列的状态需要满足1×2的长方形能够合理地摆放。这意味着,在同一列中,连续的空格数量必须为偶数,因为1×2的长方形需要覆盖两个格子。如果有奇数个空格,则该列的状态为非法状态。

  3. 相邻列的状态转移

    • 在进行状态转移时,需要确保当前列的状态和前一列的状态是合法的。具体来说,当前列的状态 i 和前一列的状态 j 不应在同一个位置上都有1,即 (i & j) == 0。此外,ij 的合并状态必须是合法的(即满足所有被占用的格子组成的空隙的数量为偶数)。

  4. 状态转移方程

    • 定义 f[i][j] 表示前 i 列的状态为 j 的方案数。那么状态转移方程为:

      f[i][j] += f[i - 1][k]  // 对于所有合法的 k

    • 其中,k 是前一列的状态,state[j][k] == 1 表示状态 jk 之间可以合法转移。

代码分析

  • 状态初始化

    • state[i][j] 用于表示列状态 ij 是否可以组合为合法状态,st[i] 用于表示单列状态 i 是否合法。

  • DP 过程

    • 通过动态规划数组 f,递推计算出所有可能的合法分割方案。

  • 状态压缩的意义

    • 通过位运算,我们将二维的棋盘问题转化为一维的状态表示,并且通过位操作来判断状态的合法性和相邻列状态的转移。这种做法可以极大地减少我们对状态的存储和处理需求,避免暴力解法中的重复计算。

状态压缩的步骤总结:

  1. 列状态的表示:每列的状态用二进制表示,位数等于行数 N

  2. 列状态的合法性判断:每列必须能被1×2的长方形完全覆盖,空格数必须为偶数。

  3. 状态转移的合法性判断:相邻列的状态不能冲突,且合并后的状态必须是合法的。

  4. 通过DP递推解决:使用 f[i][j] 表示前 i 列状态为 j 的方案数,最终输出结果 f[m][0] 即为棋盘的合法分割方案数。

小结

通过状态压缩,我们将棋盘列的排列组合转化为位运算操作,压缩了存储和计算量,同时动态规划利用状态转移方程来高效地计算出分割方案的数量。 代码from栗子ing

import java.util.*;
​
public class Main{public static void main(String[] args) {Scanner sca = new Scanner(System.in);int N = 12, M = 1 << N;long[][] f = new long[N][M];int[][] state = new int[M][M];boolean[] st = new boolean[M];while (true) {int n = sca.nextInt();int m = sca.nextInt();//当 n 和 m 同时为 0 结束循环if (n == 0 && m == 0) {break;}for (int i = 0; i < 1<< n; i ++ ) {int cnt = 0;    //  表示的是当前 前面0的个数boolean flag = true;for (int j = 0; j < n; j ++ ) { // 从上倒下判断有多少个0// 判断现在这位是不是 1if ((i >> j & 1) == 1 ) {//如果是1,判断1前面0的个数是不是偶数,奇数的话就结束if ((cnt & 1) == 1) { // & 1  等于 1 就是奇数,反之是偶数flag = false;break;}cnt = 0;} else {cnt++; // 如果当前不是1 ,则 0 的个数 +1}}// 最后还要判断一下最后一层0的个数是不是奇数if ((cnt & 1) == 1) flag = false;// 最后将这一种状态存入st数组,表示true 合法 或者false非法st[i] = flag;}// 这是 i- 1 到 i列的方块for (int i = 0; i < 1 << n; i ++ ) {// 将所有的状态清零,因为多组数据防止上一组的影响Arrays.fill(state[i], 0); for(int j = 0; j < 1 << n; j ++ ) {// 当满足 1. i 和 j没有相交(同一行的两列不能连续放置方块会重叠)//        2. i - 1 列的空格数是不是偶数if ((i & j) == 0 && st[i | j]) {state[i][j] = 1;}}}for (int i = 0; i < N; i ++ ) {// 因为有多组数据,防止上一组数据的干扰Arrays.fill(f[i], 0);}// 边界,横着在第一列方只有一种方案就是 什么也不放 f[0][0] = 1;// 最后的 DP部分//为什么从1开始呢,因为从0开始的话,我们定义的f[m][j]就是前i - 1列已经摆好//如果是0开始,就会从-1个开始摆好,因为我们没有-1列,所以从1开始for (int i = 1; i <= m ; i ++ ) {// 枚举 i - 1 到 i 的所有方案啊for (int j = 0; j < 1 << n; j ++) {//枚举 i- 2 到 i- 1 的所有方案啊for (int k = 0; k < 1 << n; k ++ ) {// 现在的方案等于前面每种k方案的总和if (state[j][k] == 1 ) {f[i][j] += f[i - 1][k];}}}}System.out.println(f[m][0]);}}
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[数据集][目标检测]瞳孔虹膜检测数据集VOC+YOLO格式8768张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;8768 标注数量(xml文件个数)&#xff1a;8768 标注数量(txt文件个数)&#xff1a;8768 标注…

【微信小程序】自定义组件 - 数据、方法和属性

1. data 数据 2. methods 方法 在小程序组件中&#xff0c;事件处理函数和自定义方法需要定义到 methods 节点中&#xff0c;示例代码如下&#xff1a; 3. properties 属性 在小程序组件中&#xff0c;properties 是组件的对外属性&#xff0c;用来接收外界传递到组件中的数…

[Algorithm][贪心][跳跃游戏][加油站][单调递增的数字][坏了的计算器]详细讲解

目录 1.跳跃游戏1.题目链接2.算法思路详解3.代码实现 2.加油站1.题目链接2.算法原理详解3.代码实现 3.单调递增的数字1.题目链接2.算法原理详解3.代码实现 4.坏了的计算器1.代码实现2.算法原理详解3.代码实现 1.跳跃游戏 1.题目链接 跳跃游戏 2.算法思路详解 贪心&#xff1…

记忆化搜索与状态压缩:优化递归与动态规划的利器

记忆化搜索是解决递归和动态规划问题的一种高效优化技术。它结合了递归的灵活性和动态规划的缓存思想&#xff0c;通过保存已经计算过的子问题结果&#xff0c;避免了重复计算&#xff0c;大幅提升了算法的效率。当问题状态复杂时&#xff0c;状态压缩技术可以进一步优化空间使…

Java数组05:Arrays类

本节内容视频链接&#xff1a;Java数组07&#xff1a;Arrays类讲解_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV12J41137hu?p57&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 Java中的‌Array类是一个针对数组进行操作的工具类&#xff0c;‌提供了排序、‌…

算法_字符串专题---持续更新

文章目录 前言最长公共前缀题目要求题目解析代码如下 最长回文子串题目要求题目解析代码如下 二进制求和题目要求题目解析 字符串相乘题目要求题目解析代码如下 前言 本文将会向你介绍有关字符串的相关题目&#xff1a;最长公共前缀、最长回文子串、二进制求和、字符串相乘。本…

GDB的基本使用(1)

我有话说 因为时间和精力原因&#xff0c;本文写的虎头蛇尾了&#xff0c;除了启动调试与程序执行以外只有少量截图演示&#xff0c;只是简单的说明。如果有需要可以联系我&#xff0c;我有时间的话会把演示补上&#xff0c;谢谢理解。 启动调试与程序执行 启动调试并传递参数…

linux环境下通过源码编译的方式安装mysql8.0.16版本

文章目录 前言一、资源准备1.源码下载2.依赖命令安装2.1 安装依赖包2.2 安装高版本gcc2.3 安装高版本cmake 二、编译安装mysql1.解压mysql-boost-8.0.16安装包2.执行编译命令3.执行make命令4.执行make install 命令5.编译安装完成后结果检查 三、初始化mysql1. 创建数据相关目录…

在ubuntu16.04下使用词典工具GoldenDict

前言 本来要装有道词典&#xff0c;结果发现各种问题&#xff0c;放弃。 网上看大家对GoldenDict评价比较高&#xff0c;决定安装GoldenDict 。 安装 启动 添加词库 GoldenDict本身并不带词库&#xff0c;需要查词的话&#xff0c;必须先下载离线词库或者配置在线翻译网址才…

SQL每日一练-0816

今日SQL题&#xff1a;计算每个项目的年度收入增长率 难度系数&#xff1a;&#x1f31f;☆☆☆☆☆☆☆☆☆ 1、题目要求 计算每个项目每年的收入总额&#xff0c;并计算项目收入环比增长率。找出每年收入增长率最高的项目。输出结果显示年份、项目ID、项目名称、项…

OD C卷 - 查找一个有向网络的头节点和尾节点

查找一个有向网络的头节点和尾节点 &#xff08;200&#xff09; 在一个有向图中&#xff0c;有向边用两个整数表示&#xff0c;第一个整数表示起始节点&#xff0c;第二个整数表示终止节点&#xff1b;图中只有一个头节点&#xff0c;一个或者多个尾节点&#xff1b;图可能存…

RTX 40全系10款显卡《黑神化:悟空》测试:打开DLSS3帧生成 性能直翻4倍

一、前言&#xff1a;《黑神话&#xff1a;悟空》临近发布 RTX 40系显卡表现如何&#xff1f; 2020年8月20日&#xff0c;游戏科学发布了《黑神话&#xff1a;悟空》的首个实机演示预告&#xff0c;惊艳了整个游戏行业&#xff01; 以往&#xff0c;很多人认为国产开发商做不出…

华为数通方向HCIP-DataCom H12-821题库(更新单选真题:1-10)

第1题 1、下面是一台路由器的部分配置,关于该配置描述正确的是? [HUAWEllact number 2001 [HUAWEl-acl-basic-2001]rule 0 permit source 1.1.1.1 0 [HUAWEl-acl-basic-2001]rule 1 deny source 1.1.1.0 0 [HUAWEl-acl-basic-2001]rule

Java实现STL中的全排列函数next_permutation()

目录 一、引言 二、全排列函数next_permutation() 三、next_permutation()的使用 四、Java实现next_permutation() 五、使用next_permutation()实现全排列 一、引言 相信很多小伙伴们都做过全排列的算法题&#xff0c;输入一个n&#xff0c;输出1~n的全排列。对于这个问题…

jemeter压力测试入门

1. 安装jemeter的压缩包并且解压 点击运行 2. 添加线程组 3. 线程组的参数设置 4. 添加http请求 5. 填写请求信息 添加监听器——结果树&#xff08;结果&#xff09;&#xff0c;聚合报告&#xff08;吞吐量报告&#xff09; 6. 通过cvs数据文件设置&#xff0c;配置元件&…

ARM 裸机与 Linux 驱动对比及 Linux 内核入门

目录 ARM裸机代码和驱动的区别 Linux系统组成 内核五大功能 设备驱动分类 内核类型 驱动模块 驱动模块示例 Makefile配置 命令 编码辅助工具 内核中的打印函数 printk 函数 修改打印级别 ​编辑 打印级别含义 驱动多文件编译 示例 模块传递参数 命令行传递参数…

jmeter简单发送接口

一、安装jmeter 拥有java环境&#xff0c;再下载jmeter 安装之后解压到本地&#xff0c;jmeter中的bin目录配置到环境变量中 之后可以通过cmd中 jmeter.bat命令运行 二、利用jmeter发送接口请求 1、添加线程组 添加->线程->线程组 2、添加http请求 添加->取样器-&g…

利用Matlab求解高阶微分方程(ode45)

1、高阶微分方程的基本概念 二阶以及二阶以上的微分方程称之为高阶微分方程&#xff0c;一般来说&#xff0c;微分方程的阶数越高&#xff0c;求解的难度也就越大。求高阶方程的一个常用方法就是降低阶数。对二阶方程 &#xff0c;如果能用变量代换把它化成一阶方程&#xff0c…

学习记录——day33 HTTP

目录 一、HTTP相关概念 二、客服端请求 1、请求首部 2、 响应首部 三、线程实现HTTP并发服务器 一、HTTP相关概念 1、HTTP&#xff0c;全称Hyper Text Transfer Protocol&#xff0c;用于万维网&#xff08;world wide web&#xff09;进行超文本学习的传输协议 2、HTTP属…

计算xpclr

1.conda安装xpclr 首先安装流程很轻松 conda create -n xpclr -c bioconda xpclr conda activate xpclr xpclr -h 2.按照要求准备文件 XPCLR - 简书 (jianshu.com) 根据教程准备文件&#xff0c;vcf&#xff0c;计算好的map&#xff0c;以及样本文件txt 其实官网也有介绍…