《劍指offer》中題14
給你一根長度為n的繩子,請把繩子剪成m段(m、n都是整數,n>1並且m>1),每段繩子的長度記為k[0],k[1],...,k[m]。請問k[0] x k[1] x ... x k[m]。可能的最大乘積是多少?例如,當繩子的長度是8時,我們把它剪成長度分別為2、3、3的三段,此時得到的最大乘積是18。
第一種解法:遞迴自頂向下解法
當第一次看到這個問題的時候第一反應的什麼呢?有點蒙,再細細想想這個問題。將一根繩子分為m段其乘積最大,m段必定有兩部分組成定為m1,m2,要想m段乘積最大,就需要保證m1段中的分割乘積是最大,同理m2也需一樣。先看下面圖,n第一次分割之後如下:
備註,第一行和下面組合不是兩個值直接相乘,而是拆分之後最大的值相乘,例如 m1 長度為 6, m2 長度 n-6,m1分割最大乘積是9(3*3)
最大的結果肯定為其中乙個組合,即:f(n) = max(f(i) x f(n-i));同理 f(i),f(n-i)又可以往下切割,直到最小單位位置,最小切割單位為 f(1) = 1,f(2) = 2, f(3) = 3。
分析完成腦海立馬想到的是遞迴解法,遞迴簡單易懂。
第二種解法:遞推自下而上解法
遞迴很好理解,但遞迴重複了大量計算,隨著n值增大,效率呈指數下降。遞迴是自頂向下,那有沒有自下而上的解法呢?
回顧一下斐波那契數列第二種解法,它是每次計算f(k),f(k+1)的值,通過f(k),f(k+1)可以求出f(k+2),通過f(k+1),f(k+2) 可以求出f(k+2),一直到f(n)。
同理我們要求f(k) = max(f(i) x f(k-i)),我們需要提前記錄f(i),f(k-i)最大的值,迴圈遍歷計算之後就能求出f(k)最大值,同理以此往下計算到f(n)為止就可以了
第三種解法:貪心解法(更像是數學推導的結果)
當 n >= 5 時,可以證明:2(n-2) > n && 3(n-3) > n。也就是說當繩子剩下的長度大於或者等於5的時候,我們可以將繩子剪成長度為 3 或 2。另外,當 n >= 5時,3(n-3) >= 2(n-2),因此我們應該將可能多的剪成長度為3繩子段。
需要注意的是 第一種和第二種解法屬動態規劃,第三屬貪心演算法。後續會詳細講解。
多領悟裡面的思想。
#include #include // ********************動態規劃********************
// 解法一: 遞迴自頂向下解法
int maxproductsubset(int length)
int maxproductarr = ;
if (length < sizeof(maxproductarr) / sizeof(maxproductarr[0]))
int maxproduct = 0;
for (int i = 1; i <= length / 2; ++i)
return maxproduct;
}int maxproductaftercutting_solution1(int length)
int maxproductarr = ;
if (length < sizeof(maxproductarr) / sizeof(maxproductarr[0]))
int maxnum = 0;
for (int i = 1; i <= length / 2; ++i)
return maxnum;
}// 解法二: 遞推自下而上解法
int maxproductaftercutting_solution2(int length)
products[i] = max;
}max = products[length];
delete products;
return max;
}// ********************貪婪演算法********************
// 解法三: 貪心演算法
int maxproductaftercutting_solution3(int length)
// ********************測試**********************
void test(const char* testname, int length, int expected)
int result2 = maxproductaftercutting_solution2(length);
if(result2 == expected)
std::cout << "solution2 for " << testname << " passed." << std::endl;
else
std::cout << "solution2 for " << testname << " failed." << std::endl;
int result3 = maxproductaftercutting_solution3(length);
if(result3 == expected)
std::cout << "solution3 for " << testname << " passed." << std::endl;
else
std::cout << "solution3 for " << testname << " failed." << std::endl;
}void test1()
void test2()
void test3()
void test4()
void test5()
void test6()
void test7()
void test8()
void test9()
void test10()
void test11()
int main(int agrc, char* ar**)
執行結果: 剪繩子 演算法 從剪繩子看動態規劃和貪心演算法
給你一根長度為 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.思路 動態規劃法 package jianzhi offer public class cut shengzi private static intmatproductaftercutting 1 int length if length 2 if length 3 將最優解儲存在陣列中 int...
動態規劃與貪心演算法 剪繩子問題
問題 給你一根長度為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.動態規劃 求乙個問題的最優解 最...