15. 剪繩子 - 動態規劃
問題描述
給你一根長度爲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、比如有一段長度爲n的繩子,我們現在要剪第一刀,我可以選擇下第一刀的地方有1 ~ n-1這些地方;比如長度爲10的繩子,我第一刀可以在1~9這些地方下刀,共9種方式。
2、第一刀下去後,繩子分成兩部分,假設在i處下刀,繩子兩部分就分別爲:[0 ~ i]與[i ~ n],長度分爲表示爲i與n-i;那麼找出第一刀最合適的位置,其實就是找i在哪下刀,可以使得[0 ~ i]與[i ~ n]的乘積最大,函數表示爲:
f(n) = max(f(i) * f{n-i))
3、那麼如何判斷i處切最大呢?這個時候,我們就要知道,[0 ~ i]這個長度的繩子,任意方式切,最大的乘積是多少;假如說,當我們要切一個長度爲10的繩子:
切成1和9與4和6,兩種方式,哪個乘積更大?
回答:不光要考慮第一刀後兩個繩子的大小,還要考慮到,9、4、6這三種情況下,因爲第一刀切出的繩子長度是否可以再切第二刀,使它有更大的乘積,比如將9再切成333,6切成4*2,哪個更大?
這種情況下,我們可以發現,無論再怎麼切,一定是越切越短,那麼我們是否可以將小於給定長度的繩子的每一個長度的最大乘積都求出來?
即:長度爲10的繩子,我們就計算出:長度1~9這9種長度的繩子,每種長度的最大乘積是多少。
要求長度9的繩子的最大乘積,我們要知道1 ~ 8各個長度的最大乘積,要知道長度8的最大乘積,就要知道1 ~ 7長度的各個最大乘積,以此類推。
代碼
public static int maxProductAfterCutting_solution(int length) {
if (length < 2) {
return 0;
}
if (length == 2) {
return 1;
}
if (length == 3) {
return 2;
}
int[] products = new int[length + 1];
products[0] = 0;
products[1] = 1;
products[2] = 2;
products[3] = 3;
int max = 0;
for (int i = 4; i <= length; i++) {
max = 0;
for (int j = 1; j <= i / 2; j++) {
int product = products[j] * products[i - j];
if (max < product) {
max = product;
}
products[i] = max;
}
}
return products[length];
}