聲明:題目和程序來自《劍指offer》,註釋和分析爲自己所寫備忘,侵刪。
動態規劃
題目:給你一根長度爲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。
分析:動態規劃,POJ上有好多這種題,主要是考慮能否將大問題可以化爲幾個小問題的集合,一般是化爲兩個小問題。在能夠劃分成小問題之後,再考慮是否需要存儲劃分的路徑,怎麼存儲,是否需要存儲小問題的解以加快計算速度等。
對於這個題,f(n) = max( f(i) x f(n-i)), 0<i<n。
貪婪算法:不同於動態規劃的遍歷,貪婪每一步都求出對於當前步最優的解,不需要考慮前一步和後一步。貪婪算法的對最優解得判斷是由數學方式計算的。
動態規劃解題思路:
int maxProductAfterCutting_solution(int length)
{
if(length <2)//長度最小爲2
return 0;
if(length ==2)
return 1;//長度等於2的解
if(lentgh ==3)
return 2;//長度等於3的解
int* products = new int[length + 1];//存放最優解得矩陣
products[0] = 0;
products[1] = 1;
products[2] = 1;
products[3] = 2;
int max = 0;
for(int i=4;i <=length; i++){//從4開始求最大值,這裏沒有在劃分m的條件下,也沒有存儲最大的劃分方式,只是單單求最大值。
max = 0;
for(j = 1; j<=i/2; j++){
int temp = products[j] *products[i-j];
if(max <temp)
max = temp;
products[i] = max;
}//求products[i]的最大值
}
max = products[length];
delete[] products;
return max;
}
貪婪算法代碼:
(當繩子長度>=5時,儘可能多的剪長度爲3的繩子,當剩下長度爲4時,將繩子剪爲兩段長度爲2的繩子)
int maxProductAfterCutting(int length)
{
if(length<2)
return 0;
if(length == 2)
return 1;
if(length == 3)
return 2;
int timesOf3 = length/3;
if(length - timesOf3 * 3 ==1)//剩餘長度爲4時,剪成2x2的
timeOf3 -= 1;
int timeOf2 = (length -timesOf3*3)/2;
return (int)(pow(3, timesOf3))*(int)(pow(2, timesOf2));
}
貪婪算法依據:
繩長n>=5時,2(n - 2)> n,且3(n - 3)> n,且3(n - 3)> 2(n - 2)。在f(n) = f(i)*f(n - i)的情況下,分成3和n-3的乘積最大。爲什麼這樣分?在n>7時分成4(n - 4)不更大嗎?或者5(n - 5),並不是,5(n-5)可以比2*3(n-5)小,4(n - 4)等同於2*2(n-4),其他6(n-6)同理。至於這個公式怎麼想到的,在考慮動態規劃時,想到劃分1(n - 1)、2(n - 2)、3(n - 3)、4(n - 4)、5(n - 5),但是從4開始都可以拆爲2,3組合,且2,3組合大於單個數字,根據f(n) = f(i)*f(n-i),考慮將所有的化爲2,3 組合。
這種前提下是沒有限定劃分段數m,僅求最大數,若段數m限定,可以根據
直接求解。