网易练习题1-合唱团

在这里插入图片描述
<此为小编分享对此题的理解,若涉及侵权行为,请通知小编下架>
这个题目我们采用动态规划的方法。动态规划在我的理解是把一个问题分为多个阶段去求解,即从下往上也可以从上往下地递推。
这个题目我们可以看作是从下往上的递推。我们是要求n个学生中选k个学生的能力值乘积最大,假设我们现在知道了n个学生中选k-1个学生的能力值乘积的最大值x,那么我们只需要在剩下的学生中找到能力值与x相乘最大的学生。
如:求出n个学生中选1个学生的最大值,可以求出n个学生中选2个学生的最大值…求出n个学生中选k个学生的最大值。

代码分析:
定义一个二维数组f[n][k],n表示总人数,k表示选取的人数,代码中的left用于寻找第k-1个学生的位置。
注意点1:能力值有可能为负数,所以定义第二个二维数组,用于存放每次运算得到的最小值。最小值若与下一个负数相乘可能为最大值。
注意点2:数组下标是从0开始的,需要注意数组下标不能等于n,k。

import java.util.Scanner;

public class Main {
      public static void main(String[] args){
          Scanner sc = new Scanner(System.in);
                while(sc.hasNext())
                {
          	int n = sc.nextInt();//总人数
                int[] arr = new int[n];//存储能力值
                for(int i=0;i<n;i++)
                {
                    arr[i] = sc.nextInt();
                }
                int k = sc.nextInt();//总选取人数
                int d = sc.nextInt();//间隔
                long[][] f = new long[n][k];
                long[][] g = new long[n][k];
                int last;//最后一个人的位置
                int k1;//选取人数
                int left;//第last-1个人的位置
                for(last=0;last<n;last++)//倘若选取人数为1
                {
                    f[last][0]=arr[last];
                    g[last][0]=arr[last];
                }
                for(k1=1;k1<k;k1++)//确定选取人数
                {
                    for(last=k1;last<n;last++)//确定最后一个人的位置
                    {
                        long max = Long.MIN_VALUE;
                        long min = Long.MAX_VALUE;
                        for(left=Math.max(k1-1,last-d);left<=last-1;left++)//left为第last-1个人的位置开始寻找第k个学生的位置                           
                         {
                            if(max<Math.max(f[left][k1-1]*arr[last],g[left][k1-1]*arr[last]))//两个数组分别与第k个学生相乘,求最大的那个值
                            {
                                max = Math.max(f[left][k1-1]*arr[last],g[left][k1-1]*arr[last]);
                            }
                            if(min>Math.min(f[left][k1-1]*arr[last],g[left][k1-1]*arr[last]))
                            {
                                min = Math.min(f[left][k1-1]*arr[last],g[left][k1-1]*arr[last]);
                            }
                        }
                        f[last][k1] = max;//确定last为最后一个学生时,能力的最大值为max
                        g[last][k1] = min;//确定last为最后一个学生时,能力的最小值为max
                    }
                }
                long result = Long.MIN_VALUE;
                //在选取人数大于1后,f[last][k]的意思是last个学生中选取的k个学生的能力值乘积的最大值
                for(last=k-1;last<n;last++)//确定last在区间(k-1,n-1)的最大值,最后一个学生的下标为n-1
                {
                    if(result<f[last][k-1])
                    {
                        result = f[last][k-1];
                    }
                }
                System.out.println(result);
            }
      }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值