合唱团——网易2017内推笔试编程题

链接: https://www.nowcoder.com/questionTerminal/661c49118ca241909add3a11c96408c8
来源:牛客网

有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这k 个学生的能力值的乘积最大,你能返回最大的乘积吗? 


分析:

本题采用动态规划的思想。

对该问题进行分解:从n个学生中选择k个,可以看成是:先从n个学生里选择最后一个,然后在剩下中选择k-1个,并且让这1个和前k-1个满足约束条件。(相邻两个学生的位置编号差不超过d的约束)

记第k个人的位置为one,则可用f[k][one]表示从n个人中选择k个学生的情况,它的子问题应为从one前面的left个人里面选择k-1个,这里left表示k-1个人里面的最后一个(即第k-1个)人的位置,因此子问题可表示为f[k-1][left]。

one表示最后一个人,其取值范围为[1,n]。left表示第k-1个人所处的位置,需要和第k个人位置差不超过d,因此有max(k-1,one-d},k-1表示此时从第0个同学到第k-2个同学都已经找到,先找第k-1个同学。

在n和k定了之后,需要求解出n个学生选择k个能力值乘积的最大值。因为能力值有正有负,所以
当one对应的学生能力值为正时,
f[k][one] = max{f[k-1][left]*arr[i]}(min{k-1,one-d}<=left<=one-1);
当one对应的学生能力值为负时
f[k][one] = max{g[k-1][left]arr[i]}(min{k-1,one-d}<=left<=one-1);
此处g[][]是存储n个选k个能力值乘积的最小值数组

package DongtaiGuihua;

import java.util.Scanner;

public class HeChangTuan {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        while (scanner.hasNext()){
            int num=scanner.nextInt();  //学生人数
            int[] cap=new int[num];   //能力值
            for(int i=0;i<num;i++){
                cap[i]=scanner.nextInt();
            }
            int k=scanner.nextInt();   //所需学生数
            int d=scanner.nextInt();   //相邻位置编号最大之差

            //dp[j][i]表示选了j个学生并以第i个同学结尾,所产生的最大(小)乘积。
            long[][] dp_max=new long[k+1][num+1];
            long[][] dp_min=new long[k+1][num+1];

            for(int i=1;i<=num;i++) {
                dp_max[1][i] = cap[i - 1];
                dp_min[1][i] = cap[i - 1];
            }
            for(int j=2;j<=k;j++){
                for(int i=j;i<=num;i++){
                    long tempmax=Long.MIN_VALUE;
                    long tempmin=Long.MAX_VALUE;
                    for(int left=Math.max(j-1,i-d);left<=i-1;left++){  //此时i是最后一个同学的位置,往前找前一个j-1同学位置。此时从第0个同学到第j-2个同学都已经找到,先找第j-1个同学。
                        tempmax=Math.max(tempmax,Math.max(dp_max[j-1][left]*cap[i-1],dp_min[j-1][left]*cap[i-1]));
                        tempmin=Math.min(tempmin,Math.min(dp_max[j-1][left]*cap[i-1],dp_min[j-1][left]*cap[i-1]));
                    }
                    dp_max[j][i]=tempmax;
                    dp_min[j][i]=tempmin;
                }
            }
            long res=Long.MIN_VALUE;
            for(int i=k;i<=num;i++){
                if(res<dp_max[k][i]){
                    res=dp_max[k][i];
                }
            }
            System.out.println(res);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_27139155/article/details/80729652