核心思想:从集合角度来分析DP问题

在我们遇到的DP问题中,一般都是求在一个有限集内的最值,但是这些方案数量一般都是指数级别的,想要一个一个查找出来不太可能。所以DP方法是用来优化这种寻找最优方案的过程的。

DP问题一般来说分析时都要经过两个阶段:

  1. 状态表示(化零为整):指把一些具有相似点的方案,划分为一个子集,然后用一个状态来表示它。现在假设我们的状态表示为 \(f[i]\)。

    状态表示要从两个角度来分析:

    1. 集合:\(f[i]\) 表示的集合就是:所有满足xxx条件的集合。正是因为我们的 \(f[i]\) 可以表示一类东西而不是一个东西,这样就可以达到优化的作用。
    2. 属性:也就是我们状态存的这个值是这个集合的什么东西,也就是最大值/最小值/数量等等。
  2. 状态计算(化整为零):先看一下 \(f[i]\) 表示的所有状态是什么:

    比如说是这个集合:

    然后把它划分成一个个子集(如果求的是数量那么必须不重复;如果求的是最大值就不用管了),我们的划分依据是:寻找最后一个不同点。

    如果要求整个状态的最大值的话,我们只需要把这个状态的所有子集的最大值求出来,再把整个集合的最大值求出来就可以了。这样,我们就成功把一个大问题分解成一个个小问题求解出来了。

举例:01背包问题

开始使用闫氏DP分析法!

  1. 状态表示:\(f[i][j]\)

    1. 集合:所有只考虑前 \(i\) 个物品,且总体积不超过 \(j\) 的选法的集合。
    2. 属性:Max(最大值)
  2. 状态计算:

    想要取得最大值,只需要得出左边集合的最大值和右边集合的最大值就可以了。

    我们来看一下这两个子集分别是什么

    完成!这样我们就成功地把这个问题推出来了。

这个问题还可以再继续优化,目前的状态表示是二维的,但是每次我们只会用到第 \(i - 1\) 层的东西,这样就可以用滚动数组来优化了。还有,我们的状态表示的第二维要么是用自己,要么是用比自己小的数,我们就可以从大到小枚举体积,换为一维数组来存储状态。

为什么可以这样呢?如果用一维数组来存储状态,状态转移方程就是这样了:

\(f[j] = max(f[j], f[j - v[i]] +w[i])\)

因为我们是从大到小枚举体积,所以这时的 \(f[j - v[i]]\) 还没有在第 \(i\) 层被更新过;所以此时它存的就是上一层的 \(f[j - v[i]]\),也就是 \(f[i - 1][j - v[i]]\)。

代码:

朴素版

#include <iostream>
#define N 1010
using namespace std;
int n, m;
int v[N], w[N];
int f[N][N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> v[i] >> w[i];
for (int i = 1; i <= n; ++i)
for (int j = 0; j <= m; ++j) {
f[i][j] = f[i - 1][j]; // 左半边的子集
if (j >= v[i]/*右半边的方案是存在的*/) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}
cout << f[n][m] << '\n';
return 0;
}

优化版

#include <iostream>
#define N 1010
using namespace std;
int n, m;
int v[N], w[N];
int f[N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) cin >> v[i] >> w[i];
for (int i = 1; i <= n; ++i)
for (int j = m; j >= v[i]/*就相当于在循环里判断一句j >= v[i]*/; --j)
f[j] = max(f[j], f[j - v[i]] + w[i]);
cout << f[m] << '\n';
return 0;
}

有了闫氏DP分析法,从此再也不怕DP问题!

AcWing - 闫氏DP分析法的更多相关文章

  1. 【闫式dp分析法】

  2. Procrustes Analysis普氏分析法

    选取N幅同类目标物体的二维图像,并用上一篇博文的方法标注轮廓点,这样就得到训练样本集: 由于图像中目标物体的形状和位置存在较大偏差,因此所得到的数据并不具有仿射不变性,需要对其进行归一化处理.这里采用 ...

  3. 从Elo Rating System谈到层次分析法

    1. Elo Rating System Elo Rating System对于很多人来说比较陌生,根据wikipedia上的解释:Elo评分系统是一种用于计算对抗比赛(例如象棋对弈)中对手双方技能水 ...

  4. AX中四种库存ABC分析法原理研究

    库存ABC分类,简单的说就是抓大放小,是为了让我们抓住重点,用最大精力来管理最重要的物料,而对于不太重要的物料则可以用较少的精力进行管理.它和我们平常说的八二法则有异曲同工之妙. 既然要应用库存ABC ...

  5. 黑盒测试用例设计方法&理论结合实际 -> 边界值分析法

    一. 概念 边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法.通常边界值分析法是作为对等价类划分法的补充,这种情况下,其测试用例来自等价类的边界. 二. 边界值分析法的应用 根据大量的测 ...

  6. 帕累托分析法(Pareto Analysis)(柏拉图分析)

    帕累托分析法(Pareto Analysis)(柏拉图分析) ABC分类法是由意大利经济学家帕雷托首创的.1879年,帕累托研究个人收入的分布状态图是地,发现少数人收入占全部人口收入的大部分,而多数人 ...

  7. SWOT分析法

    SWOT(Strengths Weakness Opportunity Threats)分析法,又称为态势分析法或优劣势分析法,用来确定企业自身的竞争优势(strength).竞争劣势(weaknes ...

  8. 5W1H分析法

    "5W1H分析法"也叫"六何分析法",它是一种分析方法也可以说是一种创造技法.是对选定的项目.工序和操作,都要从原因(Why).对象(What).地点(Wher ...

  9. 【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集

    近来复习编译原理,语法分析中的自上而下LL(1)分析法,需要构造求出一个文法的FIRST和FOLLOW集,然后构造分析表,利用分析表+一个栈来做自上而下的语法分析(递归下降/预测分析),可是这个FIR ...

  10. 2017人生总结(MECE分析法)

    试着用MECE分析法对人生的整个规划做一下总结.作为技术人员,其实除了编码架构能力之外,分析问题的能力的重要程度也会随着职业发展越来越重要.<美团点评技术博客>说这几天要在黄金时段头版头条 ...

随机推荐

  1. Python潮流周刊#6:Python 3.12 有我贡献的代码!

    你好,我是猫哥.这里记录每周值得分享的 Python 及通用技术内容,部分为英文,已在小标题注明.(标题取自其中一则分享,不代表全部内容都是该主题,特此声明.) 首发于我的博客,https://pyt ...

  2. 一文搞懂V8引擎的垃圾回收机制

    前言 我们平时在写代码的过程中,好像很少需要自己手动进行垃圾回收,那么V8是如何来减少内存占用,从而避免内存溢出而导致程序崩溃的情况的.为了更高效地回收垃圾,V8引入了两个垃圾回收器,它们分别针对不同 ...

  3. 【PAT】1001 害死人不偿命的(3n+1)猜想(动态更新)

    卡拉兹(Callatz)猜想: 对任何一个正整数 n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把 ( 砍掉一半.这样一直反复砍下去,最后一定在某一步得到 n=1.卡拉兹在 1950 年的世界 ...

  4. zabbix 监控nginx

    nginx内置了一个status状态的功能,通过配置可以看到nginx的运行情况,status显示的内容包括当前连接数,处于活动状态的连接数,已经处理的请求数等等,可以利用这个功能编写zabbix监控 ...

  5. Paimon读取流程

    查询模式 先来看看官网关于Paimon查询模式的说明 可以看到查询模式围绕snapshot展开, 而snapshot分了两种一种是Last compact snapshot和 last snapsho ...

  6. 解决redis从服务器未配置主服务器密码导致数据未同步&磁盘饱满问题

    问题前置场景 本人前几天买了一台2核4G+40G磁盘空间的云服务器用来学习使用,在服务器上安装了docker.为了学习redis主从架构,使用docker-compose部署了一主二从三台redis服 ...

  7. PHP支付接口签名生成数据

    <?php //作者主页 https://www.woailunwen.com $pay_memberid = '商户号'; $pay_orderid = '订单号'; $pay_amount ...

  8. gitlab配置环境及pycharm配置

    一.gitlab介绍 GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务 git.gitlab.GitHub的简单区别 git 是一种基于命令 ...

  9. 【Redis】模糊查询

    Redis模糊查询 1.支持的通配符*.?.[] 2.通配符* a.单个 * 模式 # 查询所有的key keys * b.双 * 模式,匹配任意多个字符 # key中含有rich的key keys ...

  10. 快速实现 CDN 直播

    功能简介 ZEGO Express SDK 支持推流到 CDN(Content Delivery Network,内容分发网络),包括转推 CDN 和直推 CDN 两种功能.开发者基于该功能可打通 R ...