题目:给你一根长度为n的绳子,请把绳子剪成m段 (m和n都是整数,n>1并且m>1)每段绳子的长度记为k[0],k[1],…,k[m]. 请问k[0]k[1]…*k[m]可能的最大乘积是多少?例如,当绳子的长度为8时,我们把它剪成长度分别为2,3,3的三段,此时得到的最大乘积是18.
采用动态规划解决此问题
分析:采用动态规划解决问题的特点:
1.假设第一刀剪在长度为i(0<i<n)的位置,于是把绳子剪成了长度为 i 和 n-i 的两段,我们想要得到整个问题的最优解f(n),那么要用同样的方法将 i 和 n-i段切割成若干段。使他们各自剪出的每段绳子乘积最大。
也就是说,整体问题的最优解是依赖各个子问题的最优解
f(4)=max{f(1)f(3), f(2)f(2)}
f(5)=max{f(1)f(4), f(2)f(3)}
...
f(n)=max{f(1)f(n-1), f(2)f(n-2), f(3)f(n-3), ..., f(i)(fn-i), ...}
因为需要保证f(i)f(n-i)不重复,就需要保证i<=n/2,这是一个限制条件,求1~n/2范围内的乘积,得到最大值
得到状态转移方程:
f(n)=max(f(i)xf(n-i)),其中0<i<n
/**
* 动态规划
*
* f(n) = max(f(i)*f(n-i))
*/
public class demo1 {
public int cutScopeSolution(int length){
if(length<2){
return 0;
}else if(length==2){
return 1;
}else if(length==3){
return 2;
}
//创建辅助数组 存储 已产生的最小值
int[] arr = new int[length + 1];
arr[0]=0;
arr[1]=1;
arr[2]=2;
arr[3]=3;
/**
*
* 这些情况下,不剪的时候长度比剪的时候长,所以作为初始条件
* 这些都是子问题最优解,因为是子问题,所以这些情况可以不剪,因为可以看成它是分割后的一部分
*/
int max = 0;
for(int i = 4;i<=length;i++){
max = 0;
for(int j = 1;j<=i/2;j++){
int temple = arr[j]*arr[i-j];
if(max<temple){
max=temple;
}
arr[i]=max;
}
}
return arr[length];
}
}