题目描述
有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗?
输入描述:
每个输入包含 1 个测试用例。每个测试数据的第一行包含一个整数 n (1 <= n <= 50),表示学生的个数,接下来的一行,包含 n 个整数,按顺序表示每个学生的能力值 ai(-50 <= ai <= 50)。接下来的一行包含两个整数,k 和 d (1 <= k <= 10, 1 <= d <= 50)。
输出描述:
输出一行表示最大的乘积。
示例1
输入
3 7 4 7 2 50
输出
49
思路 :
这是一个最优化的问题 求最大的乘积 ;可以用动态规划 难点是如何构造出传递函数;
f(i,k)表示的是从第i个学生开始 选择k个学生的乘积值;(因为是乘积 中间有可能出现负负得正的情况 所以状态方程可以有两个 数组;)
代码如下:
#include<iostream>
#include <vector>//容器;
#include <assert.h>//断言
#include<ctime>//时间
#include<cmath>//数学
#include <string>//字符串
#include <algorithm>//算法头文件;
#include<limits.h>
using namespace std;
using ll=long long ;
//=========main函数
int main()
{
int n;
cin >> n;
vector<int>nums(n);
for (int i = 0; i < n; i++)
cin >> nums[i];
int k, d;
cin >> k >> d;//表示的是两个学生的位置不能超过d;
assert(k >= 1 && k <= 10);
assert(d >= 1 && d <= 50);
vector<vector<long long>> dp_max(n, vector<long long>(k + 1, 0));
vector<vector<long long>> dp_min(n, vector<long long>(k + 1, 0));
for(int i=0;i<n;i++)//初始化;
dp_max[i][1]=dp_min[i][1]=nums[i];
for(int i=0;i<n;i++)//dp[i][j]表示的是从第i位学生开始 选取j个学生的乘积;
{
for(int j=2;j<=k;j++)
{
for(int m=1;m<=d&&m<=i;m++)//这一层比较难 是一个动态的数值;在学生之间的编号差;
{
dp_max[i][j]=max(dp_max[i][j],max(dp_max[i-m][j-1]*nums[i],dp_min[i-m][j-1]*nums[i]));//求最大的乘积
dp_min[i][j]=min(dp_min[i][j],min(dp_max[i-m][j-1]*nums[i],dp_min[i-m][j-1]*nums[i]));//求最小的乘积;
}
}
}
ll res=INT_MIN;
for(int i=0;i<n;i++)
res=max(res,dp_max[i][k]);//结果中一定是要从最大的乘积中找了 就不需要最小乘积了
cout<<res<<endl;
}