[Mdp] lc100386. 超级饮料的最大强化能量(dp+状态表示+状态转移+状态机dp+周赛411_2)

1. 题目来源

链接:100386. 超级饮料的最大强化能量

2. 题目解析

一道不错的 T2,直接上来就是 dp。想着会不会是一个贪心题目,就写了写,WA 了 2 发后实在顶不住了,换个思路考虑,dp,秒过…


思路:

  • 状态定义:f[i][j]:选到 i 位置时,且选择 j 饮料的最大值。j 在这里只能去 0,1 代表 a、b 两种饮料。
  • 状态转移,思考方式1:
    • f[i][0] = max(f[i-1][0]+a[i), f[i-1][1]); 代表 如果走到了 a[i] 这个位置,那么状态必然由 a[i-1] 或者 b[i-1] 转移过来。如果是 a[i-1] 的话,可以将 f[i-1][0] 累加起来,因为是同种饮料。如果是 b[i-1] 的话,那么当前的这个 a[i] 实际上是不可选的,因为是饮料切换。但是可以继承 f[i-1][1] 另一种饮料的最大值。
    • 另一种同理。
  • 状态转移,思考方式2:
    • f[i][0]=max(f[i-1][0]+a[i], f[i-2][1]+a[i]); 这个思考方式是从 i 的转移过程来考虑,他前一个肯定是从 当前饮料的 i-1 或者另一个饮料的 i-2 处过来的。

至于状态初始值的定义,因为第二种状态转移思路有个 i-2 这个操作,且当 i=1 的时候,i-2 还是会受到这个影响,此时可以考虑将空间统一开大一个,做一下偏移即可,也是一个常用技巧吧。


  • 时间复杂度 O ( n ) O(n) O(n)
  • 空间复杂度 O ( n ) O(n) O(n)

仅考虑前一位的状态转移:

class Solution {
public:
    long long maxEnergyBoost(vector<int>& energyDrinkA, vector<int>& energyDrinkB) {
        typedef long long LL;
        int n = energyDrinkA.size();
        LL f[n][2];
        f[0][0] = energyDrinkA[0]; f[0][1] = energyDrinkB[0];
        for (int i = 1; i < n; i ++ ) {
            // 对于第 i 杯饮料。
            // i 喝了,意味着 i-1 也喝了。 状态为:f[i-1][0] + a[i] 
            // i 不喝,则 i-1 喝的是另一种,饮料品类变化,次轮不加当前值。状态为:f[i-1][1]
            f[i][0] = max(f[i - 1][0] + energyDrinkA[i], f[i - 1][1]);
            f[i][1] = max(f[i - 1][1] + energyDrinkB[i], f[i - 1][0]);
        }

        return max(f[n - 1][0], f[n - 1][1]);
    }
};

考虑前两位的状态转移:

class Solution {
public:
    long long maxEnergyBoost(vector<int>& energyDrinkA, vector<int>& energyDrinkB) {
        typedef long long LL;
        int n = energyDrinkA.size();
        LL f[n + 1][2];
        memset(f, 0, sizeof(f));
        f[1][0] = energyDrinkA[0];
        f[1][1] = energyDrinkB[0];

        for (int i = 2; i <= n; ++i) {
            f[i][0] = max(f[i - 1][0], f[i - 2][1]) + energyDrinkA[i - 1];
            f[i][1] = max(f[i - 1][1], f[i - 2][0]) + energyDrinkB[i - 1];
        }

        return max(f[n][0], f[n][1]);
    }
};

原生,未额外开辟数组:

class Solution {
public:
    long long maxEnergyBoost(vector<int>& energyDrinkA, vector<int>& energyDrinkB) {
        typedef long long LL;
        int n = energyDrinkA.size();
        LL f[n + 1][2];
        memset(f, 0, sizeof(f));
        f[1][0] = energyDrinkA[0];
        f[1][1] = energyDrinkB[0];

        for (int i = 2; i <= n; ++i) {
            f[i][0] = max(f[i - 1][0], f[i - 2][1]) + energyDrinkA[i - 1];
            f[i][1] = max(f[i - 1][1], f[i - 2][0]) + energyDrinkB[i - 1];
        }

        return max(f[n][0], f[n][1]);
    }
};
  • 23
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值