问题如下:
Give you a rope of length n, please cut the rope into m segments (m and n are integers, n>1 and m>1). The length of each segment is denoted by k[0], k[1], …, k[m]. What is the maximum possible product of k[0]k[1]…*k[m]? And analyze the time complexity of your solution
翻译:
给你一根长度为 n 的绳子,请把绳子切成 m 段(m 和 n 是整数,n > 1和 m > 1)。每个段的长度用 k [0] ,k [1] ,… ,k [ m ]表示。K [0] k [1] … k [ m ]的最大可能乘积是多少?并分析解决方案的时间复杂性
注意至少割一刀
解决思路和方案如下:
用一个dp数组记录从0到n长度的绳子剪掉后的最大乘积,也就是dp[i]表示长度为i的绳子剪成m段后的最大乘积,初始化dp[2] = 1
/*求n长度绳子至少剪一刀的最大乘积,要由比n小的这么一个长度的绳子得来
* 对一个n长度的绳子,其子问题的长度范围是0-n,代表0长度到n长度的绳子,我们用i来表示这些长度,i的范围是[0,n]
* 因为至少剪一刀,长度至少为1,但这个1,对最后的乘积没有任何作用,白白消耗了长度1的绳子
* 所以我们从长度为2开始剪,设剪下的这一段长度为j,j的范围是[2,i-1],剪完一刀的长度不可能是i,那就等同于没剪
* 当剪下一段长度j的绳子后,后面还有i-j长度的绳子,有两种选择,要么不剪了乘积是i*(i-j),要么对后面i-j长度的绳子再剪至少一刀,那么长度是i*dp[i-j]
* 我们取更大值max(i*(i-j),i*dp[i-j]),但这只是对于一个长度为i的绳子,其中的某一种剪法得来的当前较大值。
* 比如说长度i为5,j从2开始,我们得到的只是长度为5的绳子,剪成2和3,或者剪成2,2,1(最dp[3]展开后是2,1)这两种方案的较大值是6.dp[5]暂记为6
* 但还有j从3开始的,j从4开始的那些方案,所以目前这个6只是长度为5的绳子,枚举出的方案之一,我们要的是:这些方案中哪一个使dp[5]最大
* 所以这个dp[5]=6,只是当前较大值,后面还需要更新,尽管后续方案可能都比不上这个6,但我们还需要比较,因为那是长度很特殊,比如这个长度5
* j从2开始,执行完后dp[5]是6
* j从3开始,max(3*2,3*dp[2]),是6
* j从4开始,max(4*1,4*dp[1]),是4。这里dp[1]=0,1长度还要求至少剪一刀,没法剪,根本不满足题意要求,我们把他当做0,当做null更好理解,但这里计算可能会出问题,我没有尝试
* 所以我们在j从2开始那个方案中求得的6,就是最后的最大值了,但也有特殊的,大家可以自己举一下例子。
*/
import java.util.Scanner;
public class lab2_1 {
public static int findmax(int n)
{
int[] dp=new int[n+1];
dp[0]=dp[1]=0;
dp[2]=1;
for(int i=3;i<=n;i++)
{
for(int j=2;j<i;j++)
{
dp[i]=Math.max( dp[i], Math.max( j*(i-j),j*dp[i-j] ) );
}
}
return dp[n];
}
public static void main(String[] args) {
// TODO 自动生成的方法存根
//用一个dp数组记录从0到n长度的绳子剪掉后的最大乘积,也就是dp[i]表示长度为i的绳子剪成m段后的最大乘积,初始化dp[2] = 1
/*求n长度绳子至少剪一刀的最大乘积,要由比n小的这么一个长度的绳子得来
* 对一个n长度的绳子,其子问题的长度范围是0-n,代表0长度到n长度的绳子,我们用i来表示这些长度,i的范围是[0,n]
* 因为至少剪一刀,长度至少为1,但这个1,对最后的乘积没有任何作用,白白消耗了长度1的绳子
* 所以我们从长度为2开始剪,设剪下的这一段长度为j,j的范围是[2,i-1],剪完一刀的长度不可能是i,那就等同于没剪
* 当剪下一段长度j的绳子后,后面还有i-j长度的绳子,有两种选择,要么不剪了乘积是i*(i-j),要么对后面i-j长度的绳子再剪至少一刀,那么长度是i*dp[i-j]
* 我们取更大值max(i*(i-j),i*dp[i-j]),但这只是对于一个长度为i的绳子,其中的某一种剪法得来的当前较大值。
* 比如说长度i为5,j从2开始,我们得到的只是长度为5的绳子,剪成2和3,或者剪成2,2,1(最dp[3]展开后是2,1)这两种方案的较大值是6.dp[5]暂记为6
* 但还有j从3开始的,j从4开始的那些方案,所以目前这个6只是长度为5的绳子,枚举出的方案之一,我们要的是:这些方案中哪一个使dp[5]最大
* 所以这个dp[5]=6,只是当前较大值,后面还需要更新,尽管后续方案可能都比不上这个6,但我们还需要比较,因为那是长度很特殊,比如这个长度5
* j从2开始,执行完后dp[5]是6
* j从3开始,max(3*2,3*dp[2]),是6
* j从4开始,max(4*1,4*dp[1]),是4。这里dp[1]=0,1长度还要求至少剪一刀,没法剪,根本不满足题意要求,我们把他当做0,当做null更好理解,但这里计算可能会出问题,我没有尝试
* 所以我们在j从2开始那个方案中求得的6,就是最后的最大值了,但也有特殊的,大家可以自己举一下例子。
*/
Scanner sc =new Scanner(System.in);
System.out.println("请输入绳子的长度n");
int n=sc.nextInt();
int result=findmax(n);
System.out.println("绳子分成若干段后的最大乘积是"+result);
}
}