剪繩子(動態規劃 貪心演算法)

2021-10-05 13:05:44 字數 2999 閱讀 5920

《劍指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.動態規劃 求乙個問題的最優解 最...