動態規划實現鋼條切割問題(Java)


動態規划算法的步驟
  1. 刻畫一個最優解的結構特征;
  2. 遞歸地定義最優解的值;
  3. 計算最優解的值;
  4. 利用計算出的信息,構造一個最優解。

鋼條切割問題描述

 (1)Serling公司購買長鋼條,將其切割為短鋼條出售。不同的切割方案,收益是不同的,怎么切割才能有最大的收益呢?假設,切割工序本身沒有成本支出。 假定出售一段長度為i英寸的鋼條的價格為p i (i=1,2,…)。鋼條的長度為n英寸。如下給出一個價格表P。

    

  給定一段長度為n英寸的鋼條和一個價格表P,求切割鋼條方案,使得銷售收益 rn 最大。(如果長度為n英寸的鋼條的價格p n 足夠大,則可能完全不需要切割,出售整條鋼條是最好的收益)

   (2)簡單給出一個例子

  考慮n=4的時候。如圖所示給出4英寸的鋼條可能的切割方案

  

  8種切割方案,根據圖中的價格表,可以看書最優策略是方案c(將鋼條切割為兩段長度為2英寸的鋼條--收益為10)

   (3)長度為n英寸的鋼條共有2 n-1 中不同的切割方案。

   如果一個最優解將總長度為n的鋼條切割為k段,每段的長度為i ,j(1≤j≤k),則有:n=i 1 +i 2 +…+i k

   得到的最大收益為:r n =p i1 +p i2 +…+p ik

  (4)對上述價格表樣例,我們可以觀察出所有最優收益值以及對應的切割方案

  r1=1; 切割方案1=1(無切割)

  r2=5; 切割方案2=2(無切割)

  r3=8; 切割方案3=3(無切割)

  r4=10; 切割方案4=2+2

  r5=13; 切割方案5 = 2+3

  r6=17; 切割方案6=6(無切割)

  r7=18; 切割方案7=1+6或者7=2+2+3

  r8=22; 切割方案8=2+6

  r9=25; 切割方案9=2+6

  r10=30; 切割方案10=10(無切割)

  (5)對於長度為n(n≥1)的鋼條,設r n 是最優切割的收益對最優切割,若其首次切割在位置i,鋼條被分成長度為i和n-i的兩段,有:r n= r i + r n-i

  一般情況,任意切割點j都將鋼條分為兩段,長度分別為j和n-j,1≤j≤n。令r j 和r n-j 分別是這兩段的最優切割收益,則該切割可獲得的最好收益是:r’ n = r j + r n-j所以有

  

鋼條切割問題的遞歸求解過程

 (1)鋼條從左邊切割下長度為i的一段,然后只對右邊剩下的長度為n-i的一段繼續進行切割(遞歸求解),這個時候有

 (2)自頂向下的遞歸實現

  

 (3)但是這種算法在n比較大的情況下效率低,因為總是求解相同的子問題,反復的進行自身遞歸調用。如圖是子問題規模為n=4的情況

  

  這棵樹顯示了n=4 的時候的遞歸調用過程,每個結點的標號為對應的子問題規模n。這可遞歸調用數總共有2n-1個葉節點。

鋼條切割問題的動態規划求解

  對每個子問題只求解一次,並將結果保存下來。不必重新計算。介紹兩種方法

 (1)帶備忘的自頂向下法

  按照遞歸的形式編寫,使得子問題的求解只依賴於更小的子問題的解。當需要子問題的解的時候,只需要檢查是否已經保存過值。如果已經保存過,就直接使用,否則按照通常的方式計算解。

   下面給出算法的偽代碼

  這里實現算法(Java)

 1 static int UpDown(int num, int[] arr) {
 2     if(num == 0) return 0;
 3     if(result[num] != 0) return result[num];
 4     
 5     int temp = 0;
 6     for (int i = 1; i < num+1; i++) {
 7         int max = arr[i] + UpDown(num-i, arr);
 8         if(max > temp) {
 9             temp = max;
10         }
11     }
12     result[num] = temp; //將計算的長度為n的鋼條切割的長度用數組保存起來
13     return temp;
14 }
帶備忘的自頂向下法

 

 (2)自底向上方法

    這種方法一般需要恰當的定義子問題的規模,使得每個子問題的求解只是依賴於更小的子問題,所以可以將子問題按照規模排序,按照由小到大的順序排序。當求解某個子問題的時候,所依賴的那些更小的子問題都已經求解完畢,結果保存了。所以每個子問題只是求解一次。所依賴的前提子問題已經求解完成

   給出算法的偽代碼

  

  給出算法的具體實現(Java)

 1 static int DownUp(int num, int[] arr) {
 2     for (int i = 1; i < num + 1; i++) {
 3         int temp = 0;
 4         for (int j = 1; j <= i; j++) {
 5             int max = arr[j] + result[i - j];
 6             if(max > temp) {
 7                 temp = max;
 8             }
 9         }
10         result[i] = temp;
11     }
12     return result[num];
13 }
自底向上法(bottom-up method)

 Java實現兩種方法

 1 package cn.dp;
 2 
 3 
 4 /**
 5  * 動態規划實現實現鋼條切割問題
 6  *
 7  */
 8 public class Test1 {
 9 
10     static int[] result = {0,0,0,0,0,0,0,0,0,0,0};
11     static int[] s = {0,0,0,0,0,0,0,0,0,0,0};
12     
13     public static void main(String[] args) {
14         int[] arr = {0,1,5,8,9,10,17,17,20,24,30};
15         /*
16         System.out.println("自頂向下結果");
17         for (int i = 0; i < arr.length; i++) {
18             System.out.print("r"+ i +"=" + UpDown(i, arr)+"; ");
19         }
20         */
21         /*
22         System.out.println("自底向上結果");
23         for (int i = 0; i < arr.length; i++) {
24             System.out.print("r"+ i +"=" + DownUp(i, arr)+"; ");
25         }
26         */
27     }
28     
29     /**
30      * 自頂向下實現
31      */
32     static int UpDown(int num, int[] arr) {
33         if(num == 0) return 0;
34         if(result[num] != 0) return result[num];
35         
36         int temp = 0;
37         for (int i = 1; i < num+1; i++) {
38             int max = arr[i] + UpDown(num-i, arr);
39             if(max > temp) {
40                 temp = max;
41             }
42         }
43         result[num] = temp; //將計算的長度為n的鋼條切割的長度用數組保存起來
44         return temp;
45     }
46     
47     /**
48      * 自底向上實現
49      */
50     static int DownUp(int num, int[] arr) {
51         for (int i = 1; i < num + 1; i++) {
52             int temp = 0;
53             for (int j = 1; j <= i; j++) {
54                 int max = arr[j] + result[i - j];
55                 if(max > temp) {
56                     temp = max;
57                 }
58             }
59             result[i] = temp;
60         }
61         return result[num];
62     }
63 
64     /**
65      * 打印切割方案
66      */
67     static int DownUpPrint(int num, int[] arr) {
68         for (int i = 1; i < num +1; i++) {
69             int temp = 0;
70             for (int j = 1; j <= i; j++) {
71                 int max = arr[j] + result[i - j];
72                 if(max > temp) {
73                     temp = max;
74                 }
75                 s[i] = j;
76             }
77             result[i] = temp;
78         }
79         return result[num];
80     }
81 }
動態規划實現鋼條切割問題

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM