原文链接:https://blog.csdn.net/Sunmeok/article/details/82950091
题目:
给一段绳子长为m,我们可以剪n次(m>1,n>1),问剪得的各段绳子长度之积的长度最大为多少。
动态规划:
如果一个问题是求最优解,并且该问题能够分为多个子问题,并且 子问题之间有重叠的更小子问题
所以,在用动态规划之前先分析能否将
- 大问题分为多个小问题
- 分解后的小问题要存在最优解
- 小问题的最优解最合起来就能得到整个问题的最优解
动态规划思路:
像前面所说的我们先从大问题考虑, 假设我们在x处剪了,那么长度就是x*(m-x)
那么我们又要去查询x如何剪才能最长,m-x如何剪才能最长,这就是我们所说的小问题,这些小问题我们还能再拆解。
因此动态规划的思路就出来了:
我们可以从下到上去解决,这样避免了递归的重复性
我们设置一个数组,记录从0开始到m如何剪使得乘积最大。那么我们的数组下标i里存的值就是i长的绳子剪后得到的最长的乘积值。因为我们从0开始,这样每个长度都能求出来,求到最后一个元素就是我们需要的值
我们从绳子拆分后大于或者等于不拆分长度算起,这样就能一步一步求得所有最长长度
如果拆分后小于原先长度,那么我们不进行处理,直接返回相应长度
/** * 题目:剪一段绳子,如何剪各长乘机最大 */
public class CutRope {
public static int ropeMaxLength(int length){
int max;//max是存储某个长度的最大值
int[] lengthArr=new int[length+1];
if (length==0) {//如果长度为1,返回1
System.out.println("绳子长度不能为0");
System.exit(1);
}
if (length==1)//如果长度为1,返回1
return length;
if (length==2)//长度为2,返回1,因为我们下面的算法主体主要用来计算拆分后两段绳子乘积大于等于原绳子长度的部分
return 1;
if (length==3);
return 2;
//算法主体:我们开始求每个长度的最大值
//算法思想:我们通过两个循环,第一个循环用来比那里所有长度,内嵌循环用来遍历每个可剪点开始剪得到的所有可能值,
//我们要设置几个特殊值,首先长度大于1,我们的lengthArr[1]就应该等于1
//假设我们的长度为5,我们先剪了4和1,它的长度就是lengthArr[1]*lengthArr[4]
//照这样推理,我们就需要设置下面几个值(相当于斐波那契额数列的f(0)和f(1))
lengthArr[0]=0;
lengthArr[1]=1;
lengthArr[2]=2;
lengthArr[3]=3;//为什么有三,3和2一样,因为如果剪他们,他们就会变短。
for (int i = 4; i <=length ; i++) {
max=0;
//i除以2是因为当绳子剪后分两部分,这两部分互补,其实算一半就相当于算完了。
for (int j =1; j <=i/2 ; j++) {
if (lengthArr[j]*lengthArr[i-j]>max);//如果从当前点剪值大于之前的最大值,替换
max=lengthArr[j]*lengthArr[i-j];
}
lengthArr[i]=max;
}
return lengthArr[length];
}
}