合唱团问题(dp)
来源:互联网 发布:西安爱知 地址 编辑:程序博客网 时间:2024/05/22 11:44
1、
题目描述
输入描述:
每个输入包含 1 个测试用例。每个测试数据的第一行包含一个整数 n (1 <= n <= 50),表示学生的个数,接下来的一行,包含 n 个整数,按顺序表示每个学生的能力值 ai(-50 <= ai <= 50)。接下来的一行包含两个整数,k 和 d (1 <= k <= 10, 1 <= d <= 50)。
输出描述:
输出一行表示最大的乘积。
输入
37 4 72 50
输出
49
2、参考了他人的代码,反正是遇到dp问题,我就蒙圈....所以决定遇到的都好好分析并记录下来
code:ac
package schooloffer17;import java.util.Scanner;/** * Created by caoxiaohong on 17/10/30. * 有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生... * 动态规划 */public class Chorus { public static void main(String[] args) { Scanner scanner=new Scanner(System.in); int n; int k,d; while (scanner.hasNextInt()){ n=scanner.nextInt();//n个学生 int[] values=new int[n+1]; for(int i=0;i<n;i++){ //输入各个学生的值 values[i+1]=scanner.nextInt(); } k=scanner.nextInt();//选定学生的个数 d=scanner.nextInt();//相邻学生的之间的最大间隔 /**动态规划:为什么要有两个数组呢?因为学生的价值可能为负数,那么就要有一个数组存最大值,一个存最小值.如果学生价值为负数, 那么如果乘以一个不管是不是负数的最小值,才能得到最大值.这就是最小值数组存在的意义.**/ //因为乘积结果最大值为:Math.pow(50,10)=Math.pow(5,10)*Math.pow(10,10),所以数组类型采用long long[][] max=new long[n+1][k+1];//max[i][j]:i为组成j个人的最后一个人 long[][] min=new long[n+1][k+1];//min[i][j]:i为组成j个人的最后一个人 //显然max[i][0],min[i][0]=0,所以第1列不用初始化 //同理,第1行不用初始化. //但是第2列需要初始化 for(int i=1;i<n+1;i++){ max[i][1]=values[i]; min[i][1]=values[i]; } //dp过程: for(int j=2;j<k+1;j++){ for(int i=j;i<n+1;i++){ long max0=Integer.MIN_VALUE;//记录下面for循环中出现的最大值,然后赋值给max[i][j] long min0=Integer.MAX_VALUE;//记录下面for循环出现的最小值,然后赋值给min[i][j] //求解,当j,i值确定时,最大的分割点 for(int left=Math.max(j-1,i-d);left<i;left++){ if(max0<Math.max(max[left][j-1]*values[i],min[left][j-1]*values[i])){ max0=Math.max(max[left][j-1]*values[i],min[left][j-1]*values[i]); } if(min0>Math.min(max[left][j-1]*values[i],min[left][j-1]*values[i])){ min0=Math.min(max[left][j-1]*values[i],min[left][j-1]*values[i]); } } max[i][j]=max0; min[i][j]=min0; } } //根据对max[i][j]的定义:第i个人作为选择的j个人的最后一个人,所以此时需要对max第k+1列进行遍历,找出最大值 long result=Integer.MIN_VALUE; for(int i=k;i<n+1;i++){ //显然,第k+1列,从第k+1行开始,值才不为0;所以i从k开始. if(result<max[i][k]) result=max[i][k]; } System.out.println(result); } }}
3、再看dp分析:http://blog.csdn.net/baidu_28312631/article/details/47418773
3.1、递归到动规的一般转化方法
递归函数有n个参数,就定义一个n维的数组,数组的下标是递归函数参数的取值范围,数组元素的值是递归函数的返回值,这样就可以从边界值开始, 逐步填充数组,相当于计算递归函数值的逆过程。
3.2、动规解题的一般思路
(1)将原问题分解为子问题
把原问题分解为若干个子问题,子问题和原问题形式相同或类似,只不过规模变小了。子问题都解决,原问题即解决。
子问题的解一旦求出就会被保存,所以每个子问题只需求解一次。
(2)确定状态
在用动态规划解题时,我们往往将和子问题相关的各个变量的一组取值,称之为一个“状 态”。一个“状态”对应于一个或多个子问题, 所谓某个“状态”下的“值”,就是这个“状 态”所对应的子问题的解。
所有“状态”的集合,构成问题的“状态空间”。“状态空间”的大小,与用动态规划解决问题的时间复杂度直接相关。
整个问题的时间复杂度是状态数目乘以计算每个状态所需时间。
(3)确定一些初始状态(边界状态)的值
(4)确定状态转移方程
定义出什么是“状态”,以及在该“状态”下的“值”后,就要找出不同的状态之间如何迁移――即如何从一个或多个“值”已知的 “状态”,求出另一个“状态”的“值”(递推型)。状态的迁移可以用递推公式表示,此递推公式也可被称作“状态转移方程”。
3.3、能用动规解决的问题的特点
(1)问题具有最优子结构性质。如果问题的最优解所包含的 子问题的解也是最优的,我们就称该问题具有最优子结 构性质。
(2)无后效性。当前的若干个状态值一旦确定,则此后过程的演变就只和这若干个状态的值有关,和之前是采取哪种手段或经过哪条路径演变到当前的这若干个状态,没有关系。
- 合唱团问题(dp)
- 合唱团问题
- 合唱团 (线性dp)
- 网易合唱团问题
- 合唱团
- 合唱团
- 合唱团
- 合唱团
- 合唱团
- 合唱团
- 合唱团
- 合唱团
- 合唱团
- 合唱团
- 网易编程题(合唱团)
- 【网易】:合唱团(动态规划)
- 合唱团(2016网易编程题)
- 网易编程笔试题(一):合唱团
- jq 跳转页面
- C++中的static关键字的总结
- 81. Search in Rotated Sorted Array II
- java控制台输入示例分享
- 文章标题
- 合唱团问题(dp)
- 三行代码实现TabLayout+ViewPager的Tab滑动效果,从封装到开源
- 图中的最小生成树——Prim算法
- mysql中的问题解决
- NOIP2010 关押罪犯
- MyThread::run()
- JavaWeb从入门到放弃(2)-让本地可以访问接口
- 分享那些Web设计大神们常用的响应式框架
- MyEclipse的servers视窗出现could not create the view