前言
本篇博客记录动态规划中的简单多状态问题。
在之前的动态规划类型的题中,我们每次分析的都只是一种或者某一类的状态,定义的dp表也是围绕着一种状态来的。
现在可能对于一种状态,存在几种不同的子状态,在状态转移过程中相互影响。此时需要多个dp表相互进行状态转移。
目录
一、打家劫舍Ⅰ
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
题目解析:
根据题目,我们以实例一为例:
不同颜色的表格表示不同的房子,内显示的$数就是对应的资金,红色表示相邻房子如果同时被盗窃会触发报警。
现在小偷需要在不触发报警的条件下,一夜之内偷盗的最高金额(这一排房子)。
我们可以将题目问的问题根据表格翻译以下:从这一排表格中,在不连续取两个相邻各自内数的条件下,能够取到的最高数值和。
对于上述示例,小偷可以先取1(0号位置),然后取3(2号位置),就能够获得最高金额了。
对于动态规划题目,我们首先应该确定一个状态表示。根据题目,很简单的就可以确定:到达第i个房子后偷得得最高金额。
但是,根据题目的限制条件,影响着能否对该房子盗取的因素:相邻不能同时盗取。而这个取决于你是否对之前的房子进行了盗取。
对于到达第i个房子后偷得得最高金额状态存在两个子状态:
1.对当前房子偷取后得总共最高金额。f[i]
2.对当前房子不偷后得到得总最高金额。g[i]
这个两个状态相互制约,所以我们需要不同的dp表对其进行表示 ,可以采用上面的f和g。
确定好状态表示后,我们就需要确认状态转移方程了。
此处的状态简单,可以直接进行分析。
对于f状态(偷窃此房子),就近分析,上一次(相邻的房子)可以偷窃吗?不行,偷窃的话就会被逮住,所以只能上一次没有偷窃,加上这次偷窃的金额即可。
对于g状态(不偷窃此房子),上一次可以偷窃也可以没有偷窃,那么要得到最高,需要求max。
所以,我们的状态转移方程对于两个子状态均存在:
f[i] = g[i - 1] + nums[i];
g[i] = max(f[i - 1], g[i - 1]);
其中,nums[i]表示此次房子内的金额数。
为了防止越界,我们可以对f[0]和g[0]初始化即可。
f[0]表示对第一间房子偷:那么就是nums[0]即可;g[0]不偷就是0。
填表顺序自然是从左到右,并且两个dp表同时初始化。返回值就是max(f[n - 1], g[n - 1])即可。
编码:
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
// 创建dp表
vector<int> f(n);