题目描述
有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗?
输入描述:
每个输入包含 1 个测试用例。每个测试数据的第一行包含一个整数 n (1 <= n <= 50),表示学生的个数,接下来的一行,包含 n 个整数,按顺序表示每个学生的能力值 ai(-50 <= ai <= 50)。接下来的一行包含两个整数,k 和 d (1 <= k <= 10, 1 <= d <= 50)。
输出描述:
输出一行表示最大的乘积。解题思路:一开始没想出来较好的策略,果断暴力深搜,遍历所有情况找出最大值,结果不出所料,过了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;
}