首页 > 其他分享 >常见dp问题

常见dp问题

时间:2023-04-29 23:55:05浏览次数:33  
标签:状态 常见 问题 枚举 答案 区间 dp

dp的引入

动态规划(简称dp), 是指把一个问题分解为若干个子问题, 通过局部最优解得到全局最优的一种算法策略或者说一种思想方法. 简单来讲, 就是用一个数组表示我们要求的问题的答案, 如果知道前一个问题的答案, 就可以推出后一个问题的答案

dp有以下几个常见的概念:

  1. 状态: 指当前所考虑的子问题的情况. 例如背包的已用体积, 区间的起止点, 以及用状态压缩手段压缩后的状态
  2. 状态转移: 指由前一个子问题的答案推出当前问题的答案. 一般来讲会由一个表示赋值的等式给出, 称为状态转移方程
  3. 无后效性: 指当前子问题的处理策略与后边问题的解答无关. 要记住我们是从子问题的答案推出新问题的答案, 与这个子问题的答案怎么来无关

dp一般有以下三个步骤:

  1. 设计状态: 指设计出合适的dp数组以及规定dp数组的含义. 设计出的dp数组要能够形容各种状态并且能无后效性地在状态之间进行转移
  2. 推理状态转移方程: 顾名思义, 关键在于如何从已知问题的答案推出当前问题的答案, 有的时候需要多个方程, 有的时候一个方程要包含多个子状态
  3. 确定边界条件: 递推的初值或者说记忆化搜索的回溯条件, 以及各个数组的初值



基础线性dp

线性dp往往指在一个序列上进行的dp, 当然也可能有两个甚至多个序列. 一般来讲, 线性dp的三个步骤分别有以下特点:

设计状态: 至少有一维表示当前考虑的对象在数列上的位置

状态转移: 必须找到这条线上前面的位置的dp值来推出当前位置的dp值

边界条件: 第一个位置单独讨论




基础区间dp

区间dp可以视作线性dp的一个分支, 之所以把它单独列出来是因为区间dp的解法比较特殊, 同时也比较固定. 区间dp与其他线性dp不同的地方在于它的状态是以序列上的一个区间来表示的, 而且大区间的答案可以由小区间的答案得到

区间dp的基本思路:

设计状态: 至少要有 dp[l][r] 两维分别表示区间的左端点和右端点

状态转移: 一般通过枚举区间 [l,r] 之间的点 k[l,r] 分成 [l,k][k+1,r] , 然后用dp[l][k]dp[k+1][r] 推出 dp[l][r]

边界条件: 区间 l==r 时, dp[l][r] 可以从 a[l] 得出(或者为初值)

区间dp的枚举顺序往往很有趣. 根据dp顺序的原则, 执行赋值时等号右边的dp值一定要是已经算出来了的结果. 所以如果只是简单地从 1~n 分别枚举 l , r , k 就会出错, 这里给出两种常用的枚举方法:

  1. 首先枚举区间长度 len : 1 ~ n , 然后枚举起点 l : 1 ~ n , 这样可以算出终点 r = l + len -1 , 最后枚举断点 k : l ~ r . 注意终点 r 不能大于序列总长度 n
  2. 首先倒序枚举起点 l : n ~ 1 , 然后枚举终点 r : l ~ n , 最后枚举断点 k : l ~ r

如果两种枚举都不喜欢, 那么也可以用记忆化搜索




计数类dp

所谓计数类dp就是常说的统计可行解数目的问题, 区别于求解最优解, 此类问题需要统计所有满足条件的可行解, 而求解最优解的dp问题往往只需要统计子问题时满足不漏的条件即可, 但是计数类dp需要满足不重不漏的条件, 是约束最高的

我们要求解此类问题一个重要的点就是如何划分子问题, 然后做到不重不漏, 大部分情况下我们想到的方法, 同一个解可能会被多次统计, 这是不合理的




数位统计dp

数位是指把一个数字按个、十、百、千等等一位位地拆开, 关注它每一位上的数字. 如果拆的是十进制数, 那么每一位数字都是 0 ~ 9 , 其他进制可类比十进制

数位dp: 用来解决一类特定问题, 这种问题比较好辨认, 一般具有这几个特征:

  1. 要求统计满足一定条件的数的数量(即, 最终目的为计数)
  2. 这些条件经过转化后可以使用 数位 的思想去理解和判断
  3. 输入会提供一个数字区间(有时也只提供上界)来作为统计的限制
  4. 上界很大(比如 \(10^{18}\) ), 暴力枚举验证会超时

数位dp的基本原理:

考虑人类计数的方式, 最朴素的计数就是从小到大依次加一. 但我们发现对于位数比较多的数, 这样的过程中有许多重复的部分. 例如, 从 7000 数到 7999 , 从 8000 数到 8999 和从 9000 数到 9999 的过程非常相似, 它们都是后三位从 000 变到 999 , 不一样的地方只有千位这一位, 所以我们可以把这些过程归并起来, 将这些过程中产生的计数答案也都存在一个通用的数组里. 此数组根据题目具体要求设置状态, 用递推或dp的方式进行状态转移

数位dp中通常会利用常规计数的技巧, 比如把一个区间内的答案拆成两部分相减 (即 ans[l,r] = ans[0,r] - ans[0,l-1] )

那么有了通用答案数组, 接下来就是统计答案. 统计答案可以选择记忆化搜索, 也可以选择循环迭代递推. 为了不重不漏地统计所有不超过上限的答案, 要从高到低枚举每一位, 再考虑每一位都可以填哪些数字, 最后利用通用答案数组统计答案




状态压缩dp

dp的时候需要设计状态, 但是有的状态会很复杂. 对于复杂的状态, 也许就不能再像以前那样用一个 i 简单表示. 或许这个状态表示一个有 n (n \(\leqslant\) 16)个元素的集合, 甚至包含了每一个元素的情况. 为了应对这种情况, 我们可以利用状态压缩和位运算, 让一个数字表示一个集合.

状态压缩dp也需要三个步骤:

设计状态: 至少有一维是用一个数字(二进制)表示一个集合

状态转移: 考察每一个决策对集合的影响, 经常使用位运算进行转移

边界条件: 当集合为空或者说只有一个元素之类的

特别注意: 状态压缩是指数级的算法, 所以适合状态压缩的题往往有一个维度的数字很小(比如 n \(\leqslant\) 12 , n \(\leqslant\) 16)




树形dp

设计状态: 至少有一维表示当前正在考虑的树上节点 p

状态转移: 一般使用递归(深搜)由 p 的子节点的dp值得出 p 的dp值

边界条件: 叶子节点没有儿子, 可以只由叶子节点的值得出叶子的dp值



标签:状态,常见,问题,枚举,答案,区间,dp
From: https://www.cnblogs.com/evilboy/p/17364740.html

相关文章

  • 2023.17 6个问题让chatgpt帮你搞懂新行业
    1、介绍一下麦肯锡通过搞懂一个行业100个关键词来快速了解这个行业的方法。2、根据各项调查、行业报告、新闻、研究论文帮忙整理某个行业的100个关键词,并根据关联性强弱分类。3、用一句话来定义或概述上述100个关键词。4、行业中领先的前10位公司是哪些?5、哪些因素会阻碍行业的进......
  • 想要硬件设备更快,你需要了解这些性能问题!
    1前言完整的性能分析案例的第一部分,打开首页接口做压力场景,分析性能问题。将看到各种基础硬件设施层面的性能问题,如由虚机超分导致的性能问题、CPU运行模式下的性能问题、IO高、硬件资源耗尽但TPS很低的问题等。如你从零开始做一个完整项目,这些问题很可能是你首先要面对的。把它们......
  • js常见混淆加密技术
    下面,我将通过一个案例来演示如何使用JavaScript混淆加密技术来保护你的网站。假设你有一个网站,其中包含一个登录页面,该页面的JavaScript代码如下所示:functionlogin(username,password){if(username==="admin"&&password==="123456"){alert("登录成功!");}els......
  • 背包问题
    背包问题是一种组合优化的NP完全问题.问题可以描述为:给定一组物品,每种物品都有自己的体积和价值,在限定的总体积内,我们如何选择,才能使得物品的总价值最高.背包九讲①01背包问题有N件物品和一个容量是V的背包,每件物品只能使用一次第i件物品的体积是vi......
  • Python+UDP+Threading
    Python+UDP+Threading近期用pythonsocket使用TCP协议做了一个小型的数据收发服务器,后来由于在实际场景中使用时,出现网络不佳导致出现错误的情况,改成了使用UDP协议重做了一版,总体效果变好了。下面是通用代码,实际使用时在这基础上进行修改即可。#-*-coding:utf-8-*-import......
  • 计数dp
    CODEFESTIVAL2016Final\(n,m\)很小,可以设很暴力的状态发现我每次就是一条路径然后回到\(1\)所在的强连通分量,不关心我现在在哪个点,所以设\(f_{i,j,k}\)表示现在走了\(i\)步,\(1\)所在的强连通分量里面有\(j\)个点,现在走了\(k\)个点还没有回到强连通分量里面转移......
  • WordPress extended XML-RPC MetaWeblog API
    XML-RPCMetaWeblogAPI«WordPressCodexWordPress.orgWordPress.orgPluginsThemesPatternsLearnSupportDocumentationForumsNewsAboutGetInvolvedFivefortheFutureShowcaseMobileHostingOpenverseGetWordPressSearch......
  • Codeforces 1804H - Code Lock(状压 dp)
    对于一种排列方案,答案显然等于相邻字符在环上对应的劣弧长度之和。然后其实你可能会想到很多状压/折半搜索方法,包括但不限于枚举一半的信息然后折半搜后一半,但稍加思考会发现这些方案都避不开记录元素之间的相对顺序,而但凡涉及到这一点,复杂度都是阶乘起步。因此我们只能另辟蹊......
  • Codeforces 1799H - Tree Cutting(树形 dp)
    思考的时候一直卡在不会在低于\(O(n)\)的时间内储存一个连通块的\(siz\)有关的信息,看了洛谷题解之后才发现我真是个小丑。树形DP。对于一条我们需要操作的边\((i,fa_i)\),我们将其分为保留子树和删除子树两种类型,对于删除子树,我们在判定其是否合法时候改为判定删除的连通块......
  • SpringBoot读取.yml配置文件最常见的两种方式-源码及其在nacos的应用
    三、第二种方式(推荐)这种方式是小编比较推荐的,虽然看似比​​@Value​​麻烦不少,但是更加的规范,在配合nacos的时候也可以动态的修改,会立即生效,一会小编带大家试一下哈!!为什么推荐这种方式呢,是因为spring他们都是使用这种方式进行配置的,所以跟着官方走不会有错的!!1.修改yml文件我们......