网易笔试题:合唱团

题目描述

有 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
解题思路:一开始没想出来较好的策略,果断暴力深搜,遍历所有情况找出最大值,结果不出所料,过了80%的数据,没找出具体错误,我猜想应该是卡在了时间复杂度的地方,代码如下:
#include<iostream>
using namespace std;
int n,k,d;
long long int MaxValue;
int Caple[60],Hash[60];
void FindMaxValue(int index,long long int sum,int step)//index表示搜索到哪个位置了,sum表示当前的最大值是多少
//step表示现在是第几个数
{
	if(step==k)
	{
		if(MaxValue<sum)
			MaxValue=sum;
		return ; 
	}
	for(int i=1;i<=d;i++)
	{
		if(index+i<=n-1&&!Hash[index+i])
		{
			Hash[index+i]=1;
			long long int Flag=sum*Caple[index+i];
			FindMaxValue(index+i,Flag,step+1);
			Hash[index+i]=0; 
		}
	}
} 
int main()
{
	MaxValue=-99999999;
	cin>>n;
	for(int i=0;i<n;i++)
		cin>>Caple[i];
	cin>>k>>d;
	for(int i=0;i<n;i++)
	{
		Hash[i]=1;
		FindMaxValue(i,(long long int)Caple[i],1);
		Hash[i]=0;
	}
	cout<<MaxValue;
} 

由于暴力深搜不可行,于是考虑动态规划(记忆化搜索),于是仿着上面的搜索过程写了下动规代码。(其实做之前我也不知道能否写出来,记得我师父教过我,动态规划的本质是记忆化搜索,搜索的参数就是动规的状态,于是乎瞬间有了思路),瞬间AC,哈哈, 代码如下:
#include<iostream>
#include<cmath>
using namespace std;
int n,k,d;
long long int MaxValue[60][60];
int Caple[60];
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>Caple[i];
		MaxValue[i][1]=Caple[i];
	}
	cin>>k>>d;
	for(int p=1;p<k;p++)//p表示当前搜索的步数(类似于深搜的step)
		for(int i=0;i<n-1;i++)//n表示枚举的能力值
		{
			for(int j=1;j<=d;j++)//d表示状态的转移条件
			{	
				if(i+j>=n)
					break;
				if(!MaxValue[i+j][p+1]||(MaxValue[i+j][p+1]&&abs(MaxValue[i+j][p+1])<=abs(MaxValue[i][p]*Caple[i+j]))) 
					MaxValue[i+j][p+1]=MaxValue[i][p]*Caple[i+j];
			}
		}
	long long int Max=-99999999999;
	for(int i=0;i<n;i++)
		if(Max<MaxValue[i][k])
			Max=MaxValue[i][k];
	cout<<Max<<endl;
} 

猜你喜欢

转载自blog.csdn.net/qq_33546256/article/details/81003072