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

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

3个月前 (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;
}

五、总结

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


原创内容 转载请注明出处

分享给朋友:

相关文章

IOI 1994 洛谷1216:如何用O(1)空间解决数字三角形问题?附代码实现

IOI 1994 洛谷1216:如何用O(1)空间解决数字三角形问题?附代码实现

题目重解:数字三角形是一个经典的动态规划问题,给定一个由数字组成的三角形结构,从顶部出发,每次可以移动到下方相邻的数字,最终到达底部。我们需要找到一条路径,使得路径上经过的数字总和最大。这个问题可以很...

力扣965题深度解析:单值二叉树的判断技巧

力扣965题深度解析:单值二叉树的判断技巧

重新解读题目 判断一棵二叉树是否为“单值二叉树”,即所有节点的值是否完全相同。题目看似简单,实则考验对树结构递归特性的理解。若一棵树的所有节点值相同,其必然满足:根节点与左右子树的值一致,且...

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

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

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

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

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

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

一、题目解读洛谷P4551题要求在一个无向图中,寻找任意两点路径权值异或后的最大值。题目输入为图的边信息(点数n和n-1条边),每条边包含起点、终点及权值。需输出所有路径中权值异或的最大值。问题核心在...

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

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

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

发表评论

访客

看不清,换一张

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