【状压DP】状态压缩动态规划入门超详解

这篇博客详细介绍了状态压缩动态规划(状压DP)的概念,包括什么是状态压缩,使用条件以及如何在动态规划中应用。博主结合位运算知识,通过两个入门级例题【填满棋盘】和【玉米地】,阐述了如何运用状压DP解决实际问题,强调了位运算在状态转移方程中的重要性,并提醒读者在编程实现时注意位运算的优先级和括号使用。
摘要由CSDN通过智能技术生成

感觉好多讲状压DP的博客都有点乱,我就结合各路大佬的博客,加上我自己的理解,总结出一篇博客来,供初学者参考

一、概述

1.状态压缩

状态压缩就是使用某种方法,简明扼要地以最小代价来表示某种状态,通常是用一串01数字(二进制数)来表示各个点的状态。这就要求使用状态压缩的对象的点的状态必须只有两种,0 或 1;当然如果有三种状态用三进制来表示也未尝不可。

2.使用条件

从状态压缩的特点来看,这个算法适用的题目符合以下的条件:

  1. 解法需要保存一定的状态数据(表示一种状态的一个数据值),每个状态数据通常情况下是可以通过2进制来表示的。这就要求状态数据的每个单元只有两种状态,比如说棋盘上的格子,放棋子或者不放,或者是硬币的正反两面。这样用0或者1来表示状态数据的每个单元,而整个状态数据就是一个一串0和1组成的二进制数
  2. 解法需要将状态数据实现为一个基本数据类型,比如int,long等等,即所谓的状态压缩。状态压缩的目的一方面是缩小了数据存储的空间,另一方面是在状态对比和状态整体处理时能够提高效率。这样就要求状态数据中的单元个数不能太大,比如用int来表示一个状态的时候,状态的单元个数不能超过32(32位的机器),所以题目一般都是至少有一维的数据范围很小。

3.状压DP

状压DP,顾名思义,就是使用状态压缩的动态规划。

动态规划问题通常有两种,一种是对递归问题的记忆化求解,另一种是把大问题看作是多阶段的决策求解。这里用的便是后一种,这带来一个需求,即存储之前的状态,再由状态及状态对应的值推演出状态转移方程最终得到最优解。

二、位运算

一般基础的状压就是将一行的状态压成一个数,这个数的二进制形式反映了这一行的情况。由于使用二进制数来保存被压缩的状态,所以要用到神奇的二进制位运算操作,将一个十进制数转成二进制进行位运算操作再转回十进制数。

包括

  • 按位与&(有0为0,其实就是且)
  • 按位或|(有1为1,其实就是或)
  • 按位取反~(注意负数补码的符号,最前面的第一位是1)
  • 异或^(相同为0,不同为1)
  • 左移<<
  • 右移>>

对于位运算还是不太熟悉的同学请点我复习一下

下面是由江苏省淮阴中学薛志坚同(da)学(lao)整理的一些常见操作:

在这里插入图片描述
% % % \%\%\% %%%

建议花几分钟把每一条都搞懂,然后跟我一起大(mo)赞(bai)位运算的神奇 % % % \%\%\% %%%
初试化状态的时候要看清条件,什么要,什么不要。

一般情况下要预处理前k行(k由题目定)。

Dp时题目给的条件和fit函数、state数组都要检查。

最最重要的一点:

位反(~ )  >  算术  >  位左移、位右移  >  关系运算 
>  位与  >  位或  >  位异或  >  逻辑运算

所以一般位运算最好打括号。

三、例题引入

1、入门例题【例1】填满棋盘

有一个NM(N<=5,M<=1000)的棋盘,现在有12及2*1的小木块无数个,要盖满整个棋盘,有多少种方式?答案只需要mod1,000,000,007即可。

例如:对于一个22的棋盘,有两种方法,一种是使用2个12的,一种是使用2个2*1的。

【算法分析】

在这道题目中,N和M的范围本应该是一样的,但实际上,N和M的范围却差别甚远,对于这种题目,首先应该想到的就是,正确算法与这两个范围有关!N的范围特别小,因此可以考虑使用状态压缩动态规划的思想,请看下面的图:

在这里插入图片描述

本思路来自博客动态规划之状态压缩dp入门,不过原博没有图,我帮他补个图,再优化一下内容。

假设第一列已经填满,则第二列的摆设方式,只与第一列对第二列的影响有关。同理,第三列的摆设方式也只与第二列对它的影响有关。那么,使用一个长度为 N N N的二进制数 s t a t e state state来表示这个影响,例如: 4 ( 00100 ) 4(00100) 4(00100)就表示了图上第二列的状态。

因此,本题的状态可以这样表示:

d p [ i ] [ s t a t e ] dp[i][state] dp[i][state]表示该填充第

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁凡さん

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值