剪绳子
题目描述
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
思路:
这题有两种解题思路,一种动态规划另一种是贪心。
动态规划:
因为试求绳子分解后的最大乘积,是求最优解,这符合动态规划的第一个特点。该问题的最优解依赖于小问题的最优解,符合动态规划的第二个特点。往下分解的时候有很多重复的小问题,这是动态规划的第三个特点。该题都符合,所以可以使用动态规划。
一开始先将一些特殊情况输出来,因为题目是至少要剪一到,所以长度小于2的时候返回0,没得剪。长度为2的时候返回1,长度为3的时候返回。这就是特殊值。以为4的分解有两种情况。虽然可以看出最优解,但我没有吧他归为特殊情况。建一个最优解数组,从开始往下算,算到绳子长度为n时就可以停止了。注意一点的是在剪的时候,最长剪到一半就可以了,如果超过一半,其实会和前面的重复。
贪心:
这题的贪心策略是尽量剪绳子的长度为三,剩下4的时候剪为两段2;
当你n>=5时,2*(n-2)>n并且3*(n-3)>n,当绳子长度大于5的时候就尽量剪长度为3和2的绳子,
并且3*(n-3)>2*(n-2),所以尽量剪3,不够则剪2.
动态规划:
//动态规划
public int cutRope1(int target) {
if(target<2) return 0;
else if(target==2) return 1;
else if(target==3) return 2;
int p[] = new int[target+1];
p[0]=0;
p[1]=1;
p[2]=2;
p[3]=3;
for(int i=4;i<p.length;i++){
int max=0;
for(int j=1;j<=i/2;j++){
int pmax=p[j]*p[i-j];
if(max<pmax){
max=pmax;
}
}
p[i]=max;
}
return p[target];
}
贪心:
//贪心
public int cutRope2(int target) {
if(target<2) return 0;
else if(target==2) return 1;
else if(target==3) return 2;
int num3=target/3;
if(target%3==1){
num3--;
}
int num2=(target-num3*3)/2;
int max=1;
for(int i=0;i<num3;i++){
max=max*3;
}
for(int j=0;j<num2;j++){
max=max*2;
}
return max;
}
来源:CSDN
作者:臭弟弟卑微仔
链接:https://blog.csdn.net/ChildYH/article/details/104696103