剪绳子动态规划例题(java)
给你一根长度为n的绳子,请把绳子剪成整数长度的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1]...k[m-1]。
请问k[0] × k[1] × ... × k[m-1]可能的最大乘积是多少?
例如,但绳子的长度是8时,我们把它剪成长度分别为2,3,3的三段,此时得到的最大乘积是18。
示例1:
输入:2
输出:1
解释:2 = 1 + 1,1 × 1 = 1
示例2:
输入:10
输出:36
解释:10 = 3 + 3 + 4, 3 × 3 × 4 = 36
解题思路:动态规划
对于的绳子的长度 n,当 n ≥ 3 时,可以拆分成至少两个正整数绳长的和。令k是拆分出的第一个正整数,
则剩下的部分是 n-k,n−k 可以不继续拆分,或者继续拆分成至少两个正整数的和。
由于每个正整数对应的最大乘积取决于比它小的正整数对应的最大乘积,因此可以使用动态规划求解。
创建数组dp,其中dp[i]表示将正整数i拆分成至少两个正整数的和之后,这些正整数的最大乘积。
特别地,绳子长度不能为0,如果绳子长度为1不能剪,绳子长度为2只能剪成两段,因此,dp[0] = 0, dp[1] = 1, dp[2] = 2
当 i ≥ 2 时,假设对正整数 i 拆分出的第一个正整数是 j(1 ≤ j < i),则有以下两种方案:
将 i 拆分成 j 和 i-j 的和,且 i-j 不再拆分成多个正整数,此时的乘积是 j×(i−j);
将 i 拆分成 j 和 i-j 的和,且 i-j 继续拆分成多个正整数,此时的乘积是 j×dp[i−j]。
因此,当 j 固定时,有 dp[i]=max(j×(i−j),j×dp[i−j])。由于 j 的取值范围是 1 到 i-1,需要遍历所有的 j 得到 dp[i] 的最大值,
因此可以得到状态转移方程如下:dp[i]=max{max(j×(i−j),j×dp[i−j])}
最终得到 dp[n] 的值即为将正整数 n 拆分成至少两个正整数的和之后,这些正整数的最大乘积。
public class CuttingRope {
public static void main(String[] args) {
int n = 10;
System.out.println(cuttingRope(n));
}
private static int cuttingRope(int n){
int[] dp = new int[n + 1];
dp[0] = 0;
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++){
int maxResult = 0;
for (int j = 1; j < i; j++){
maxResult = Math.max(maxResult,Math.max(j * (i - j),j * dp[i - j]));
}
dp[i] = maxResult;
}
return dp[n];
}
}