1. 程式人生 > >(動態規劃)有 n 個學生站成一排,每個學生有一個能力值,從這 n 個學生中按照順序選取kk 名學生,要求相鄰兩個學生的位置編號的差不超過 d,使得這 kk 個學生的能力值的乘積最大,返回最大的乘積

(動態規劃)有 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;
}