鋼條切割問題:給定一段長度爲n英寸的鋼條和一個價格表pi(i=1,2,...,n)求切割鋼條方案,使得銷售收益rn最大。算法
注意,若是長度爲n英寸的鋼條的價格pn足夠大,最優解可能就是徹底不須要切割。性能
思路:先將鋼條切成兩條,有n-1種方案,每一種方案的最優解都等於兩個子鋼條的最優解。咱們從這n-1個僞最優解再挑出最優的解了優化
如下是僞代碼:spa
1 CUT-ROD(p,n)3d
2 if n == 0code
3 return 0blog
4 q=負無窮io
5 for i = 1 to nclass
6 q=max(q,p[i]+CUT-ROD(p,n-i))方法
7 return q
上面只用了分治策略,這個算法的性能是不好的T(n)=2n,在子問題的求解中不少都是重複的。
動態規劃就是避免這些重複。通常有兩個思路1.記錄中間解
1 MEM-CUT-ROD
2 let r[0..n] be a new array
3 for i = 0 to n
4 r[i]=負無窮
5 return MEM-CUT-ROD-AUX(p,n,r)
6
7 MEM-CUT-ROD-AUX(p,n,r)
8 if r[n]>=0
9 return r[n]
10 if n==0
11 q=0
12 else q=負無窮
13 for i=1 to n
14 q=max(q,p[i]+MEM-CUT-ROD-AUX(p,n-i,r))
15 r[n]=q
16 return q
2.經過對問題求解順序的合理安排,達到避免重複
1 BOTTOM-UP-CUT-ROD(p,n)
2 let r[0..n] be a new array
3 r[0]=0
4 for j=1 to n
5 q=負無窮
6 for i=1 to j
7 q=max(q,p[i]+r[j-i])
8 r[j]=q
9 return r[n]
下面的僞代碼還保留了切割長度
1 EXTEND-BOTTOM-UP-CUT-ROD(p,n)
2 let r[0..n] and s[0..n] be new arrays
3 r[0]=0
4 for j = 1 to n
5 q=負無窮
6 for i =1 to j
7 if q < p[i]+r[j-i]
8 q=p[i]+r[j-i]
9 s[j]=i
10 r[j]=q
11 return r and s
12
13 PRINT-CUT-ROD-SOLUTION(p,n)
14 (r,s)=EXTEND-BOTTOM-UP-CUT-ROD(p,n)
15 while n >0
16 print s[n]
17 n=n-s[n]
使用動態規劃方法求解的最優化問題應該具有兩個要素:最優子結構和子問題重疊
c語言實現代碼;
#define MinNum -200 #define MaxNum 20 #include<stdio.h> #include<stdlib.h> int Max(int a, int b) { return a > b ? a : b; } int CUT_ROD(int p[],int n) { int q; if(n == 0) return 0; q = MinNum; for(int i = 1 ; i <= n; i++) { q = Max(q,p[i] + CUT_ROD(p,n-i)); } return q; } int Bottom_UP_ROD(int p[],int n , int r[]) { int q; for(int i = 1; i <= n ; i++) r[i] = MinNum; r[0] = 0; for(int j = 1; j <= n ; j++) { q = MinNum; for(int i = 1 ; i <= j ;i++) { q = Max(q,p[i] + r[j-i]); } r[j] = q; } return r[n]; } int MEMOIZED_CUT_ROD_AUX(int p[],int n , int r[]) { int q; if(r[n] >= 0) return r[n]; if(n == 0) q = 0; else { q = MinNum; for(int i = 1 ; i <= n ; i++) q = Max(q,p[i] + MEMOIZED_CUT_ROD_AUX(p,n-i,r)); } r[n] = q; return q; } void MEMOIZED_CUT_ROD(int p[],int n) { int r[MaxNum]; for(int i = 1 ; i <= n ; i++) r[i] = MinNum; } void EXTEND_DOWN_UP_ROD(int r[],int s[],int p[], int n) { r[0] = 0; for(int j = 1 ; j <= n ;j++) { int q = MinNum; for(int i =1 ; i <= j ; i++) { if(q < p[i] + r[j-i]) { q = p[i] + r[j-i]; s[j] = i; } } r[j] = q; } } void Print_CUT_ROD_SOLUTION(int p[], int n , int s[]) { printf("----------------------------------\n"); printf("長度爲 %d 的切割方案爲\n",n); while(n > 0) { printf("%3d",s[n]); n = n - s[n]; } printf("\n"); } int main() { int p[] = {0,1,5,8,9,10,17,17,20,24}; int r[MaxNum]; int s[MaxNum]; EXTEND_DOWN_UP_ROD(r,s,p,9); for(int i = 1; i <= 9; i++) { printf("長度爲%d的收益最大爲:%d\n",i,r[i]); } Print_CUT_ROD_SOLUTION(p,9,s); system("pause"); return 0; }