給你一根長度為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。
思路
注意
當長度大於3 f[n]才能得到繩子的最大乘積
動態規划
特征
從上往下分析問題,從下往上求解問題;
- 求一個問題的最優解;(最大值或者最小值)
- 問題能夠分解成若干個子問題,並且子問題之間還有重疊的更小的子問題
- 分解后的小問題也存在最優解,如果把小問題的最優解組合起來能夠得到整個問題的最優解,就可以使用動態規划
實現
public int cutRope(int target) {
//排除特殊情況
if (target < 2) {
return 0;
}
if (target == 2) {
return 1;
}
if (target == 3) {
return 2;
}
int[] products = new int[target + 1];
products[0] = 0;
products[1] = 1;
products[2] = 2;
products[3] = 3;
for (int i = 4; i <= target; i++) {
int max = 0;
for (int j = 1; j <= i / 2; j++) {
int product = products[j] * products[i - j];
max = Math.max(max, product);
}
products[i] = max;
}
return products[target];
}
貪婪
- 由於是乘法,那么除了1以外越多數相乘,得到的結果就越大。
- 因此從2開始考慮。但是都分成2的話必然會有奇數分成包含1的段數,因為1相當於浪費了一個乘數,所以如果最后剩1的時候我們應該將他變為3. 因此得到分成的段數長度為2,3是最好的。
- 又因為 2 * 2 * 2 < 3 * 3 說明3個2都不如2個3 ,因此應該讓3 相對來說比2 多。
- 於是讓該數對3相除,余數如果為2,則分為 1個2 ,N個3 為最優解,如果余數為1,則應分為2個2 ,N-1 個3 為最優解
實現
public int cutRope(int target) {
//排除特殊情況
if (target < 2) {
return 0;
}
if (target == 2) {
return 1;
}
if (target == 3) {
return 2;
}
int timesOf3 = target / 3;
if (target - timesOf3 * 3 == 1) {
timesOf3--;
}
int timesOf2 = (target - timesOf3 * 3) / 2;
int result = (int) (Math.pow(3, timesOf3) * Math.pow(2, timesOf2));
return result;
}
遞歸
雖然動態規划比遞歸不知高到那里去,因為遞歸有很多的重復求解情況
但是,我看互聯網上,剪繩子好像沒有人寫遞歸的解法,於是...就當看個玩
思路
f(n)=max(f(i)*f(n-i)) 0<i<n
實現
public int cutRope03(int target) {
if (target < 2) {
return 0;
}
if (target == 2) {
return 1;
}
if (target == 3) {
return 2;
}
int max = cutRope03Core(target);
return max;
}
private int cutRope03Core(int target) {
if (target < 4) {
return target;
}
int max = 0;
for (int i = 1; i <= target/2; i++) {
max = Math.max(cutRope03Core(i) * cutRope03Core(target - i), max);
}
return max;
}