核心思想:从集合角度来分析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. CF1817E Half-sum 另解与 Trygub Number

    一题水两篇怎么说. 上一篇中我们采用智慧方法减少了比较次数,避免了使用复杂的高精度数.现在我们有高论!可以做到 \(\mathrm O(\log_B V\log_2 n)\) 在某一位加或者减一个大小 ...

  2. 使用ansible-app2k8s管理和部署服务到 kubernetes

    ansible-app2k8s #1 介绍 使用 ansible 管理和部署服务到 kubernetes 适用于项目容器化,多套 k8s 环境的管理,可结合CICD工具做DevOps 来自于项目实践, ...

  3. 微服务bug之:openFeign远程调用返回类型转换异常

    楼主是在使用easyexcel导出的时候,获取数据出现这个错误,因为Spring底层是这样处理的使用LinkedhashMap来承接查询结果,导致转换异常 public List<NeedAll ...

  4. python学习笔记:继承与超类

    与java类似,继承的出现是为了提高代码的重复利用率,避免多次输入同样的代码.而超类就是java中的父类. 1.继承 要指定超类,可在定义类时,在class语句中的类名后加上超类名 基类就是超类,派生 ...

  5. .net 6 winform启动器:调用CMD命令行执行dotnet命令启动.net core程序并将控制台输出日志输出到winform textbox实现实时日志显示

    背景 历史遗留问题,生产车间运行的一个.net core signalr程序使用命令行程序启动,经常由于生产人员误操作将光标停留在控制台上导致程序假死,丢失部分测试数据,车间随便找了一台win10系统 ...

  6. 为什么Python是数据科学家的首选语言

    这篇文章全面探讨了Python作为数据科学领域首选语言的原因.从Python的历史.特性,到在数据科学中的应用实例,再到与其他数据科学语言的比较,以及在实际企业中的应用,我们深入剖析了Python的优 ...

  7. 网关冗余协议:FHRP、HSRP(思科)、VRRP、GLBP

    参考链接: CHANNEL技术与网关冗余 VRRP和HSRP的区别

  8. JDK源码-StringJoiner源码分析

    背景 功能描述:将多个元素使用指定符号前后连接为字符串:eg:1 2 3 4 5 , => 1,2,3,4,5 要点: 多个元素 指定分隔符 分隔符只在元素之间,不能作为第一或最后一个 使用方法 ...

  9. npm install -g 错误集锦

    1.切换源安装:npm config set registry http://registry.cnpmjs.org,参考http://yijiebuyi.com/blog/b12eac891cdc5 ...

  10. QMainWindow类中比较重要的方法

    方法和描述 addToolBar():添加工具栏 centralWidget():返回窗口中心的一个空间,未设置时返回NULL menuBar(): 返回主窗口的菜单栏 setCentralWidge ...