题目传送门

一、一组数组模拟状态记录

我们可以定义一个数组,为\(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\)家店铺能得到的最多现金数量。

则就会出现三种情况:

AcWing 1049. 大盗阿福_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;
}