【算法训练 (day2)】积木画(dp问题)

news2024/11/23 15:17:46

目录

一.问题

题目描述

输入格式

输出格式

输出样例 

二.解题思路

合法性判定(状态压缩):

          推导dp式:

          代码实现:


一.问题

 

题目描述

小明最近迷上了积木画,有这么两种类型的积木,分别为 I 型(大小为 2 个单位面积)和 L 型(大小为 3 个单位面积): 

 
同时,小明有一块面积大小为 2 × N 的画布,画布由 2 × N 个 1 × 1 区域构成。 
小明需要用以上两种积木将画布拼满,他想知道总共有多少种不同的方式? 
积木可以任意旋转,且画布的方向固定。

输入格式

输入一个整数N,表示画布大小。 
对于所有测试用例,1 ≤ N ≤ 10000000。

输出格式

输出一个整数表示答案。由于答案可能很大,所以输出其对 1000000007 取模后的值

3

输出样例 

5

二.解题思路

合法性判定(状态压缩):

由于上一列的摆放会影响当前列,所以我们要对每一列积木的摆放方法进行检查,剔除掉不合法的操作。这样我们就需要判断能否从上一列的状态转换到当前列的状态。由于本题画步的高度是固定的,且值很小,所以我们可以枚举这两列所有的状态。每一列有两个格子,每个格子只会有两种状态,摆放或者不摆放。这里要引入状态压缩,把这一列的两个格子分别当成二进制位,摆放的格子就是1,不摆放就是0,我们让下面的格子是低位,上面的格子是高位。这样就能组合出一个十进制数,就可以用0,1,2,3表示当前列的四种状态(因为每   一列有两个格子,每个格子有两种状态一共就是四种状态)。cdad9b34071647288f13fa7c44d8577b.png

第一种状态,两个格子都不放,十进制为0.

                                                       b71db856a89e411da293cff3a94493a8.png

                                                                                第二种状态,下面格子被占用,十进制为1

6d2d05ff6b3d4c8392ff38063d78e004.png

                                                                                第三种状态,上面格子被占用,十进制为2

3aa4473553544746854610c60f1fe760.png

                                                                               第四种状态,两个格子被占用,十进制为3

对于下一列我们也可以采取这种表达方式。所以下一列的四种状态也可以用0,1,2,3来表示,这样我们就可以通过一个二维数组f[i][j]来判断能否从当前状态转移到下一列的其他状态。我们可以让状态作为数组下表,所以状态到状态的转移就变成了下标到下标的转移。能转移记值为1,不能转移则为0.接下来我们需要判断这16种方案哪些合法。(我们取每块积木最左侧的方块作为操作)

  • 当前一列状态数为0,判断后一列状态数能否为0,1,2,3: 

c0f641f1ca4641f09f6162ded0686fb7.png

 当前列原来状态是0,由于当前列在操作过后必须要填满,否则不符合题意。当前j的状态是0.所以0状态可以转移到0状态。f[0][0] = 1

a20e9836d19140cc87a2ea0bea372975.png

 由图片可以得到从0转移到1的状态也是可以的。f[0][1]  = 1

75ee7804e8af457e8486592fe71d5a57.png

同理f[0][2]=1 

bebea9be376b4de4adcf384c6d3cbbd2.png

同样j是3的时候也是可以转化成功的 

  • 当前i状态是1的时候:

4d0a9011978344f6ade65b04bd4ee3fb.png686fd77f763b41c394be28af0f72ee5d.png

 为保证i列操作后必须要填满,只有当j满足上两种状态的时候才能转化,所以f[1][2] = 1,f[1][3] =1 

  • 当前i状态是2的时候:

其实本质和i是1的情况是一样的,只不过是反转了一下。

bffe12b483024e0c9450e5378aa33553.png

7b138da83ded486f91e3b1fd4010fae6.png

 同样可得f[2][3] =1,f[2][1] =1

  • 当i的状态是3的时候:

7cec46d849d2456ba71e6931990a2fee.png

 由于此时i已经被上一列填满了,同时我们是在对第i列进行操作,所以当前状态下无法放入任何一个积木块,j的状态只能为0

综上,我们就能得到一个关于判断状态转移是否合法的二维数组。

{1,1,1,1}

{0,0,1,1}

{0,1,0,1}

{1,0,0,0}

这样我们就能通过当前列的状态推出下一列的状态是否合法。

推导dp式:

在我们使用状态推导的时候,我们首先要确定两个问题,dp式表达的含义是什么,dp公式是什么。由于这道题求的是积木的方案数,我们可以让dp式存放状态数。由于我们是一列一列去判断的,所以我们还需要记录下当前处理到了哪一列(同时也知道了前i-1处理完毕后的状态数),同时由于第i列的摆放状态会对下一列的状态转移产生影响。我们还要知道当前的状态。所以用dp[i][j]可以表示,i是当前的列数,j是当前的状态(也就是之前的状态压缩)。假设已经处理到最后一列的最后一种状态,那么当前列的状态数就应该是当前列的其他状态数加上从上一列状态转化到当前状态时上一列的状态数(必须满足状态转移的合法性,才能加上上一列的状态数),也就是dp[i+1][k] = dp[i+1][k]+f[j][k]*dp[i][j]。同样二维数组两纬度分别表示列数和当前列状态。(k是下一列的四种状态,)所以通过三层循环,一层遍历所有的列数,一层遍历当前列的所有状态,一层遍历下一列所有的状态,通过之前枚举过的状态转移合法性数组来判断是否能从当前状态转移到目标状态,如果能转移过来就可以加上当前状态的状态数,如果不能就只能加上其他目标状态的状态数。最后要注意的一点是,我们要取的结果是dp[n+1][0],因为我们在刚进入n+1列的时候才说明n列已经全部计算完毕。

代码实现:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;

//假设前i列已经摆好了,j对应是第i行的状态
//采取状态压缩,用二进制的每一个位表示当前格子是否被占用,合成的十进制数就能表示当前状态。
//由于第i+1行的状态是由第i行决定的,第i行有四种状态,0 0,0 1,1 0,1 1,十进制就是0,1,2,3,第i+1行也有四种状态,所以一共有16种状态
//我们可以枚举出从第i 转移到 i+1的所有情况并判断这种情况是否存在,让状态作为下标,这样这个数组表示的就是能否从第i行转移到第i+1行,存在值为1,不存在值为0
int g[4][4] =
{
    {1,1,1,1},
    {0,0,1,1},          //表示能否转移到j状态的数组
    {0,1,0,1},
    {1,0,0,0},

};
 const int N = 1e7 + 10, mod = 1000000007;
 int dp[N][4];   //状态转移数组,i表示处理完i-1行,当前位于第i行,处于第j状态
int main()
{
    int len;
    cin >> len;
    dp[1][0] = 1;
    for (int i = 1; i <= len; i++)    //相当于检查三排,前i-1塞满,从j状态转移到k状态
    {
        for (int j = 0; j < 4; j++)
        {                               //k表示要向k状态转移
            for (int k = 0; k < 4; k++) //需要通过枚举数组判断当前状态能否转移过来
            {
                dp[i+1][k] = (dp[i+1][k] + g[j][k] * dp[i][j])%mod;
            }
        }
    }
    cout << dp[len+1][0];  //当我们处理到len+1的时候且当前状态为0,这意味着前len行已经铺满了,也就是我们要求的
    return 0;
}

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

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

相关文章

MySQL多表查询内连接外连接详解,join、left join、right join、full join的使用

目录 1、多表查询概览 1.1、分类 1.2、外连接的分类 1.3、常用的SQL语法标准 2、内外联接案例 2.1、初始化表 2.2、内连接 2.3、外连接案例 2.4、全连接案例 2.5、union和union all 2.6、实现MySQL全连接 2.7、内外连接面试基础 2.8、SQL99多表查询新特性 1、多表…

python入门项目:数据清洗

文章目录前言一、数据清洗是什么&#xff1f;二、重复值处理三 缺失值处理四、数据类型转换前言 本文是对数据清洗的简单学习。 本文使用的数据来源为&#xff1a;博雅读书社所提供的数据 一、数据清洗是什么&#xff1f; 数据清洗是指在数据分析或挖掘之前进行的&#xff0…

Linux Shell 实现一键部署Rabbitmq

rabbitmq 前言 RabbitMQ是实现了高级消息队列协议&#xff08;AMQP&#xff09;的开源消息代理软件&#xff08;亦称面向消息的中间件&#xff09;。RabbitMQ服务器是用Erlang语言编写的&#xff0c;而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代…

2023年企业选择云服务器配置方法教程

这篇文章主要介绍企业选择腾讯云CVM云服务器配置方法教程。现在随着互联网信息的飞速发展&#xff0c;任何企业都脱离不了互联网&#xff0c;越来越多的企业都通过互联网实施无纸化的办公&#xff0c;互联网推广一体化整体型推广、互联网电子商务。中小型企业网站如何选购云服务…

又一款 AI 应用开源了,让你的绘画作品动起来!

公众号关注 “GitHubDaily”设为 “星标”&#xff0c;每天带你逛 GitHub&#xff01;2021 年的时候&#xff0c;Meta&#xff08;前身是 Facebook&#xff09;团队发布了一款非常有趣的 AI 工具&#xff0c;叫 Animated Drawings&#xff0c;它的牛逼之处&#xff0c;在于能借…

解锁ERD Online 高级隐藏功能

ERD Online 是全球第一个开源、免费在线数据建模、元数据管理平台。提供简单易用的元数据设计、关系图设计、SQL 查询等功能&#xff0c;辅以版本、导入、导出、数据源、SQL 解析、审计、团队协作等功能、方便我们快速、安全的管理数据库中的元数据。 ERD Online 产品图鉴 ERD …

使用DVSSL证书的钓鱼网站正在增加,如何识别钓鱼网站?

信息安全是一个庞大的领域&#xff0c;其中涉及到很多知识点&#xff0c;但是大多公司都对其没有提及足够的重视&#xff0c;希望随着国内对于安全的越来越重视以及各大主流浏览器对http网站的不友好&#xff0c;更多的公司也能在信息安全领域投入越来越多的注意。 然而&#…

C++IO流

目录 1. C语言的输入与输出 2. 流是什么 3. CIO流 3.1 C标准IO流 3.2 C文件IO流 4.stringstream的简单介绍 1. C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键 盘)读取数据&#xff0c;并将值存放在变量中…

vs中的错误集合

记录在vs 中遇到的 各种错误 1&#xff1a;project.vcxproj.filters 文件出现了异常&#xff0c;发现了以前的解决方案下的筛选器竟然没有了 原因&#xff1a;合并svn的时候 .vcxproj.filters 文件出现了 合并错误(检查该文件里面是否有不一样的) 解决办法&#xff1a;解决 该文…

Centos 7 上安装 Kubernetes 1.27 集群

Centos 7 上安装 Kubernetes 1.27 集群0. 安装 "Development Tools"1. 禁用swap2. 禁用防火墙3. 将SELinux设置为permissive模式4. 安装 ipset 和 ipvsadm5. 添加网桥过滤及内核转发配置文件6. 加载 overlay、br_netfilter、ip_tables、iptable_filter 模块7. 安装 c…

js调用gpt3.5(支持流回显、高频功能)

参考链接&#xff1a;直接在前端调用 GPT-3 API 效果图&#xff1a; 查看在线demo(要梯子) 注意&#xff1a; 1. 需要apiKey&#xff0c;自用安全&#xff0c;不要给别人 2. 需要梯子 3. 选择稳定、人少的代理ip 4. 不要频繁切换ip&#xff0c;防止封号 5. api调用上限高&…

李宏毅2023机器学习作业HW03解析和代码分享

ML2023Spring - HW3 相关信息&#xff1a; 课程主页 课程视频 Kaggle link Sample code HW03 视频 HW03 PDF 个人完整代码分享: GitHub | Gitee | GitCode P.S. 即便 kaggle 上的时间已经截止&#xff0c;你仍然可以在上面提交和查看分数。但需要注意的是&#xff1a;在 kaggle…

SpringAOP入门基础银行转账实例------------事务处理

SpringAOP入门基础银行转账实例------------事务处理 AOP为Aspect Oriented Programming 的缩写&#xff0c;意思为面向切面编程&#xff0c;是通过编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 AOP编程思想 AOP面向切面是一种编程思想&#xff0c;是oop的延…

Python 字符串format()格式化 / 索引

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 为了确保字符串按预期显示&#xff0c;我们可以使用 format() 方法对结果进行格式化。 字符串 format() format() 方法允许您格式化字符串的选定部分。 有时文本的一部分是你无法控制的&#xff0c;也许它们来自数据库或…

更深度了解getchar和putchar现象

目录 前言&#xff1a; 1.getchar和putchar 1.1基本使用 1.2一些特殊打印 1.3putchar打印空格 2.深度了解现象 前言&#xff1a; 经过学习&#xff0c;总结getchar()函数和putchar()函数在搭配使用while循环的时候&#xff0c;控制台窗口光标位置的出现位置的由来。 1.…

JavaSE学习进阶day04_03 包装类

第五章 包装类&#xff08;重点&#xff09; 5.1 概述 Java提供了两个类型系统&#xff0c;基本类型与引用类型&#xff0c;使用基本类型在于效率&#xff0c;然而很多情况&#xff0c;会创建对象使用&#xff0c;因为对象可以做更多的功能&#xff0c;如果想要我们的基本类型…

蓝桥杯15单片机--超声波模块

目录 一、超声波工作原理 二、超声波电路图 三、程序设计 1-设计思路 2-具体实现 四、程序源码 一、超声波工作原理 超声波时间差测距原理超声波发射器向某一方向发射超声波&#xff0c;在发射时刻的同时开始计时&#xff0c;超声波在空气中传播&#xff0c;途中碰到障碍…

计算属性,watch和watchEffect

计算属性-computed 什么是计算属性&#xff1a; computed函数&#xff0c;是用来定义计算属性的&#xff0c;计算属性不能修改。 模板内的表达式非常便利&#xff0c;但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。 计算属性还可以依…

【目标检测论文阅读笔记】Extended Feature Pyramid Network for Small Object Detection

&#xff08;未找到代码&#xff0c;只有yaml文件&#xff09; Abstract. 小目标检测仍然是一个未解决的挑战&#xff0c;因为很难提取只有几个像素的小物体的信息。虽然特征金字塔网络中的尺度级对应检测缓解了这个问题&#xff0c;但我们发现各种尺度的特征耦合仍然会损害小…

百度飞桨paddlespeech实现小程序实时语音流识别

前言&#xff1a; 哈哈&#xff0c;这是我2023年4月份的公司作业。如果仅仅是简单的语音识别倒也没什么难度&#xff0c;wav文件直接走模型输出结果的事。可是注意标题&#xff0c;流式识别、实时&#xff01; 那么不得不说一下流式的优点了。 1、解决内存溢出的烦恼。 2、…