当前位置:首页 > 牛客 > 牛客12533题解析:动态规划求解最大乘积问题(附代码实现)

牛客12533题解析:动态规划求解最大乘积问题(附代码实现)

2个月前 (07-18)

牛客12533题解析:动态规划求解最大乘积问题(附代码实现) 牛客题解 动态规划 C++ 二维数组 第1张

一、题目解读

牛客12533题要求从n个人中选择k个人,使他们的能力值乘积最大,且相邻两人编号差不超过d。需考虑正负数的乘积组合情况,通过优化算法找到最优解。

二、解题思路

采用动态规划(Dynamic Programming)解决。定义二维数组dp_max[i][j]和dp_min[i][j],分别表示选j个人且最后一个人为i时的最大和最小乘积。通过状态转移方程,利用前j-1个人的乘积与当前能力值计算,兼顾正×正、负×负、正×负三种情况,避免重复计算。

三、解题步骤

1. 初始化:选1人时,乘积即其能力值。

2. 循环处理选j个人(2≤j≤k),当前人i从j到n遍历。

3. 前一个人l在[i-d, i-1]范围内,计算最大/最小乘积:

○ dp_max[i][j] = max(dp_max[l][j-1] * ability[i-1], dp_min[l][j-1] * ability[i-1])

○ dp_min[i][j] = min(dp_max[l][j-1] * ability[i-1], dp_min[l][j-1] * ability[i-1])

4. 最终结果:遍历dp_max[k][i](i=k到n)取最大值。

四、代码与注释

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

long long maxProduct(int n, vector<int>& ability, int k, int d) {
    // dp_max[i][j]表示选j个人,最后一个人是i时的最大乘积
    // dp_min[i][j]表示选j个人,最后一个人是i时的最小乘积
    vector<vector<long long>> dp_max(n+1, vector<long long>(k+1, LLONG_MIN));
    vector<vector<long long>> dp_min(n+1, vector<long long>(k+1, LLONG_MAX));
    
    // 初始化:选1个人时就是自己的能力值
    for(int i = 1; i <= n; i++) {
        dp_max[i][1] = ability[i-1];
        dp_min[i][1] = ability[i-1];
    }
    
    for(int j = 2; j <= k; j++) { // 选j个人
        for(int i = j; i <= n; i++) { // 当前选第i个人
            // 前一个人只能在[i-d, i-1]范围内
            int start = max(j-1, i-d); // 至少需要j-1个人
            for(int l = start; l < i; l++) {
                // 考虑三种情况:正×正,负×负,正×负
                dp_max[i][j] = max(dp_max[i][j], 
                                  max(dp_max[l][j-1] * ability[i-1], 
                                     dp_min[l][j-1] * ability[i-1]));
                dp_min[i][j] = min(dp_min[i][j], 
                                  min(dp_max[l][j-1] * ability[i-1], 
                                     dp_min[l][j-1] * ability[i-1]));
            }
        }
    }
    
    // 找出选k个人时的最大乘积
    long long result = LLONG_MIN;
    for(int i = k; i <= n; i++) {
        result = max(result, dp_max[i][k]);
    }
    return result;
}

int main() {
    int n, k, d;
    cin >> n;
    vector<int> ability(n);
    for(int i = 0; i < n; i++) cin >> ability[i];
    cin >> k >> d;
    
    cout << maxProduct(n, ability, k, d) << endl;
    return 0;
}

五、总结

本解法通过动态规划将复杂问题分解为子问题,利用状态转移优化时间复杂度。关键在于处理正负数的乘积逻辑,确保最终结果正确。代码结构清晰,注释明确,适用于同类最大乘积问题的参考与学习。


原创内容 转载请注明出处

分享给朋友:

相关文章

力扣1221:一次扫描解决分割平衡字符串 时间O(n)空间O(1)

力扣1221:一次扫描解决分割平衡字符串 时间O(n)空间O(1)

题目重解给定一个仅包含'L'和'R'的字符串,要求将其分割成尽可能多的子串,且每个子串中'L'和'R'的数量相等。例如输入"R...

力扣654:递归分治的艺术 如何用最大元素构建二叉树

力扣654:递归分治的艺术 如何用最大元素构建二叉树

题目重解我们面对一个看似简单却充满递归魅力的题目:给定一个不含重复元素的整数数组,需要构建一棵特殊的二叉树。这个树的每个父节点都必须是当前子数组中的最大元素,而它的左右子树则分别由该最大值左侧和右侧的...

手搓顺序表类代码注释与详解:从零实现动态数组(新手教程)

一、简介和特点顺序表(Sequential List)是数据结构中基础的一种线性表,其特点是将数据元素存储在连续的内存空间中。通过数组实现,支持随机访问(即通过索引直接访问元素),适用于频繁随机读取的...

NOIP 2008火柴棒等式题解(C++代码实现)  动态规划与枚举算法详解

NOIP 2008火柴棒等式题解(C++代码实现) 动态规划与枚举算法详解

一、题目解读火柴棒等式问题(NOIP 2008,洛谷P1149)要求使用给定数量的火柴棒,构造形如 A + B = C 的等式,其中A、B、C均为整数,且火柴棒总数恰好等于输入值。需统计符合条件的等式...

2024蓝桥杯省赛B组“传送阵”题解(C++代码+图论算法优化)

2024蓝桥杯省赛B组“传送阵”题解(C++代码+图论算法优化)

一、题目解读2024年蓝桥杯省B组“传送阵”题目要求处理一个包含n个节点的图,节点间存在单向传输关系。每个节点i可传送至a[i]指定的节点,形成可能存在的环结构。题目需求解从任意节点出发能到达的最长路...

【蓝桥杯2015省赛解析】生命之树:树形DP解题全攻略(洛谷P8625代码详解)

【蓝桥杯2015省赛解析】生命之树:树形DP解题全攻略(洛谷P8625代码详解)

一、题目解读    “生命之树”是一道经典的树形结构问题,要求计算一棵带权树中,以某个节点为根的最大子树权值和。题目输入为n个节点及边信息,每个节点有权值wi,...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。