1. 程式人生 > 其它 >動態規劃問題(一)最大切分段數

動態規劃問題(一)最大切分段數

動態規劃問題(一)最大切分段數

問題描述

給你一段長為 L 的木棒,現在有三種切分長度 p、q、r,你只能將這根木棒切成在這三種長度內的組合,求這根木棒最大能夠切成多少段。

比如說:現在一根長為 11 的木棒,可以切分的長度為 2、3、5,因此該木棒最多能夠被切成 5 段,分別是:{2、2、2、2、3}

解決思路

由於只能在候選的三個長度內進行組合,因此可以考慮將這根木棒遞迴地按照候選長度進行切分,然後得到最終的組合數。然而,在這裡使用遞推地方式可能會更好一些。

解決方案:在每個長度位置檢測是否能夠加上對應的候選長度,如果能加上,那麼就是能切分的段數加一,但是可能也會有其它的方案可以組合目標長度,因此需要對比得到最大值。

狀態轉換方程:

$$
f(n) = max(f(n - p), f(n - q), f(n - r)) + 1
$$

邊界分析:對於長度為 0 的木棒,不存在相對應的切分方法,因此它的組合數為 0。

實現

public class Solution {
/**
* 得到長度為 n 的木棒能夠按照候選的長度組合的最大元素個數
*
* @param n : 木棒的長度
* @param x : 可切成的候選長度 p
* @param y : 可切成的候選長度 q
* @param z : 可切成的候選長度 r
* @return : 能夠切分的最大段數
*/
public static int maximizeCuts(int n, int x, int y, int z) {
int[] dp = new int[n + 1];

// 由於有的長度是無法在當前的候選長度集合中進行切分的,因此需要考慮跳過它
for (int i = 1; i <= n; ++i)
dp[i] = -1;

// 邊界情況,長度為 0 的木棒對任何候選切分子集切分的段數都為 0
dp[0] = 0;

for (int i = 0; i <= n; ++i) {
// 如果當前訪問的長度是無法由現有的組合子集組合,那那麼就說明不能被切分,跳過它
if (dp[i] == -1) continue;

/*
如果當前的長度加上備選的切割長度要小於總共的木棒長度,
那麼就可以將組個分割的子段長度加到現有的長度上,同時增加段數
由於加上的長度結果可能由多種組合情況,因此要找到最大的組合段數
*/
if (i + x <= n)
dp[i + x] = Math.max(dp[i + x], dp[i] + 1);
if (i + y <= n)
dp[i + y] = Math.max(dp[i + y], dp[i] + 1);
if (i + z <= n)
dp[i + z] = Math.max(dp[i + z], dp[i] + 1);
}

// 如果目標段數不能由現有的組合段數組合而來,則返回 0
if (dp[n] == -1) return 0;

return dp[n];
}
}