(動態規劃)有 n 個學生站成一排,每個學生有一個能力值,從這 n 個學生中按照順序選取kk 名學生,要求相鄰兩個學生的位置編號的差不超過 d,使得這 kk 個學生的能力值的乘積最大,返回最大的乘積
第2關:最強戰隊
挑戰任務
綠盟和各大名企合作,舉辦程式設計能力大賽,需要選拔一支參賽隊伍。隊伍成員全部來自“綠盟杯”中表現優秀的同學,每個同學都根據在比賽中的表現被賦予了一個能力值。現在被召集的N
個同學已經集結完畢,他們按照編號依次站成了一排。
你需要編寫一個程式,從這N
個同學中選出S
個同學,要求選出的同學的能力值的乘積最大,且要求被選出的相鄰兩個同學的編號的差不超過D
。
程式設計要求
補全右側程式碼區中的getBestTeams(int n,int a[],int kk, int d)
函式,實現找出能力值乘積最大而且滿足編號要求的同學。將最終結果作為返回值返回,函式引數說明如下:
int n
召集到的同學的人數int a[]
各個同學的能力值(依次對應不同編號的同學,陣列的index
就是學生的編號)int kk
需要選出的同學的人數int d
相鄰同學的編號的差的最大值
測試說明
樣例1:
輸入:3 , [7,4,7] , 2 , 50
輸出:49
動態規劃,這個是演算法裡面一直比較難的,當我拿到這個題的時候,有點難以下手,雖然知道要用動態規劃但是如何用,自己完全不知道,首先想到找出這個n個數中k個最大的相乘 ,但是很遺憾不對,①要求相鄰兩個學生之間的編號差不能超過d,②能力值存在負數。 動態規劃是要將問題分解若干子問題,同時子問題之間可能存在包含,我們通常需要儲存子問題的結果。 怎麼儲存了?陣列f[n][m]表示選了n個人方案,最後一的位置為m,那f[n-1][p]就表示選了n-1個人,最後一個位置為p 怎麼分解呢?首先m個人中選n個編號差要求<=d,若已經知道選n-1人的方案,同時這個方案最後一個人的位置為p,我們只需要遍歷p+1到p+d的位置求得第n個人的位置。選n個人實際上不知道哪一個作為結尾所以會遍歷的求f[n][1]~f[n][m]的最大值 有負數怎麼辦?因為有負數所以我們在加一個數組fmin[n][m]表示m個人中選n個間隔為d最小的乘積,最小的也可能成為最大的。
#include<stdio.h> #include<ctype.h> #include<string.h> #include<stdlib.h> #include<limits.h> #include<math.h> #include<algorithm> #include<iostream> using namespace std; int getBestTeams(int n,int a[],int kk,int d){ long long res=0; long long int fmax[11][51]={0}; long long int fmin[11][51]={0}; for(int j=1;j<=kk;j++){ for(int i=1;i<=n;i++){ if(j==1){ fmax[j][i]=a[i]; fmin[j][i]=a[i]; } else{ for(int p=1;p<=d;p++) if(i-p>=1&&i-p<=n){ fmax[j][i]=max(fmax[j][i],max(fmax[j-1][i-p]*a[i],fmin[j-1][i-p]*a[i])); fmin[j][i]=min(fmin[j][i],min(fmax[j-1][i-p]*a[i],fmin[j-1][i-p]*a[i])); } } res=max(res,fmax[kk][i]); } } return res; } int main(){ int n,a[51]={0},kk,d; while(cin>>n&&n){ for(int i=1;i<=n;i++) cin>>a[i]; cin>>kk>>d; cout<<getBestTeams(n,a,kk,d)<<endl; } return 0; }