1. 程式人生 > >演算法之動態規劃-Rod cutting

演算法之動態規劃-Rod cutting

問題描述:

給定長度為n的木頭,把它切分成小段賣,不同長度的木頭價格不一樣,求最優切法。如圖1:

這裡寫圖片描述
可以劃分為如下情況
分為一份: 4 (max price:10)
分為兩份 : 1 3 or 2 2 or 3 1 (max price:10)
分為三份 : 1 1 2 or 1 2 1 or 2 1 1 (max price:7)
分為四分 : 1 1 1 1 (max price:4)
最終結果為這四種情況分割的最大售價: 10

動態規劃

找出子問題

定義

  • i:長度為i的鋼管
  • r[i]:為劃分長度為i的鋼管的最大售價和
  • p[i]: 長度為i的鋼管的價格

假設存在1in,使得長度為n的木棒最優切割r[n]=p[i]+r[ni]

反證,如果不存在,肯定存在另一個值,使得長度為i的木棒產生最優切割:與假設矛盾。

最終表示式:

r(n)=maxi=1n(p[i]+r(ni))

遞迴求解子問題

遞迴求解

cutRod(p, n){
  if n ==0
    return 0
  q = [email protected]  // 初始化為負無窮
  for i = 1 to n
    q = max(p[i] + cutRod(p, n -i))
  return q
}

動態規劃
遞迴求解的缺點是從復計算大量相同問題,動態規劃的思路是把相同的問題記錄下來,之後直接查表得到相同問題的解,避免重複計算,用空間換取時間,並且效果明顯。

upBottomCutRod(p, n) {
  let r[0...n] be a new array
  for i = 0 to n
    r[i] = [email protected]  // 初始化為負無窮
  return memorizeCutRodAux(p, n, r)
}

memorizeCutRodAux(p, n, r) {
  if r[n] >= 0
    return r[n]
  if n == 0
    q = 0
  else q = [email protected]  // 初始化為負無窮
    for i = 1 to n
        q = max(q, p[i] + memorizeCutRodAux(p, n - i, r))
  r[n] = q
  return
q } bottomUpCutRod(p, n) { let r[0...n] be a new array r[0] = 0 for j = 1 to n q = [email protected] // 初始化為負無窮 for i = 1 to j q = max(q, p[i] + r[j - i]) r[j] = q return r[n] }

合併後的最終求解方案

記錄最佳cut的方案

extendedBottomUpCutRod(p, n) {
  let r[0...n] and s[0...n] be a new array
  r[0] = 0
  for j = 1 to n   //length of rod
      q = [email protected]
      for i = 1 to j    // highest price to cut when length is j
          if(q < p[i] + r[j - i])
              q = p[i] + r[j - i]
              s[j] = i    //best place to cut when length is j
      r[j] = q
  return r[n]  
}