7.2House Robber 基本动态规划:一维
题目描述
假如你是一个劫匪、并且决定抢劫一条街道上的房子。每个房子内的钱财数量都不同。但是如果你抢了两栋相邻的房子,就会触发警报机关。求在不触发机关的情况下,最多可以抢劫多少钱。
输入输出样例
Input :[2, 7, 9, 3, 1]
Output:12
题解
定义一个数组dp,dp[i]表示抢劫到第i个房子时,可以抢劫的最大数量。要考虑dp[i],此时可以抢劫的最大数量有两种可能,一种我们选择不抢劫这个房子,此时累计的金额就得-1,也就是dp[i-1];另一种选择是抢劫这个房子,因为不能抢劫第i-1个房子,这样会触发警报,那么此前累积的最大金额只能是dp[i-2],所以得到一个状态转移方程为dp[i]=max(dp[i-1],nums[i-1],+dp[i-2])
我们利用这个状态方程就可以把逻辑问题变成数学问题然后设计算法解决了
"因为不能抢劫第i-1个房子,这样会触发警报,那么此前累积的最大金额只能是dp[i-2]"
对这句话的解释:
既然第 i-1 个房子不抢,那 "抢劫到第 i 个房子" 的最大金额,就等于 "第 i 个房子的金额" + "抢劫到第 i-2 个房子时的最大金额";这里的 "抢劫到第 i-2 个房子时的最大金额" 就是 dp[i-2] ------ 因为 dp [i-2] 已经包含了 "抢劫到第 i-2 个房子时能拿到的所有最优情况"(不管第 i-2 个房子抢没抢,它都是到 i-2 为止的最大值)
当然,这题目跟上一个一样,还是只用到pre1和pre2,两个数组,直接简化就完事了。
cpp
#include <iostream>
#include <vector>
using namespace std;
int rob(vector<int>& nums) {
if (nums.empty()) return 0;
int n = nums.size();
if (n == 1) return nums[0];
int pre2 = 0, pre1 = 0, cur;
for (int i = 0; i < n; ++i) {
cur = max(pre2 + nums[i], pre1);
pre2 = pre1;
pre1 = cur;
}
return cur;
}
int main() {
vector<int> nums = { 2, 7, 9, 3, 1 };
cout << rob(nums) << endl;
return 0;
}