一、一组数组模拟状态记录
我们可以定义一个数组,为\(f[i]\)。
\(f[i]\) 表示抢劫前\(i\)家能得到的最多现金数量。
那么我们前\(i\)家的抢劫结果就有两种情况:
第一种情况:不偷第\(i\)家店铺
那么\(f[i]=f[i−1]\);
第二种情况:偷第\(i\)家店铺
那么\(f[i]=f[i−1]+w[i]\)
(\(w[i]\) 表示第\(i\)家店铺总共的现金)
思路\(1\)出现的问题:
如果第\(i−1\)家店已经被抢了,那么如果抢了第\(i\)家,那是不符合题目要求的。
那怎么办呢?
二、二维数组模拟状态记录
我们把\(f\)数组定为二维的,即\(f[i][j]\)
我们用数组储存两种情况:偷与不偷。
\(f[i][0]\) 代表的是不偷第\(i\)家店铺能得到的最多现金数量;
\(f[i][1]\) 代表的是偷第\(i\)家店铺能得到的最多现金数量。
则就会出现三种情况:
解释:
图中红色的线是可行方案,你可以不抢第\(i−1\)家,也不抢第\(i\)家;
你可以不抢第\(i−1\)家,但抢第\(i\)家。
你可以抢第\(i−1\)家,但不抢第\(i\)家;
那么我们就可以得出状态转移方程了:
\(f[i][0] = max(f[i - 1][0], f[i - 1][1]);\)
\(f[i][1] = f[i - 1][0] + w[i];\)
三、实现代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int T; //T组数据
int n; //每一组数据的个数n
int w[N]; //每个商店的金钱数量
/**
f[i][0] 代表的是不偷第i家店铺能得到的最多现金数量;
f[i][1] 代表的是偷第i家店铺能得到的最多现金数量。
*/
int f[N][2];
int main() {
//优化输入
ios::sync_with_stdio(false);
cin >> T;
while (T--) {
cin >> n;
for (int i = 1; i <= n; i++) cin >> w[i];
//逐个把商店加入
for (int i = 1; i <= n; i++) {
//不偷i号商店,获利取原来前面i-1号商店决策完的最大值
f[i][0] = max(f[i - 1][0], f[i - 1][1]);
//偷i号商店,获利取不偷i-1号商店的决策值,再加上当前商店的金额
f[i][1] = f[i - 1][0] + w[i];
}
//最终的结果二选一
printf("%d\n", max(f[n][0], f[n][1]));
}
return 0;
}