2017年校招题 合唱团(动态规划)

题目描述

有 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;
}

猜你喜欢

转载自blog.csdn.net/langxue4516/article/details/81632822