動態規劃主要用於求解最優化問題,方法與分治法類似,也是將原問題分解成多個子問題,通過遞迴的方法求解子問題。不同之處就是動態規劃會通過增加程式空間複雜度的方式來將時間複雜度為指數級降低為多項式,通俗的講就是動態規劃會利用陣列記錄下子問題的結果,當再需要計算該子問題時直接呼叫該結果即可,就不用再去計算,從而大大降低了程式的時間複雜度。
通常按照如下4個步驟來設計乙個動態規劃演算法:
1.刻畫乙個最優解的結構特徵。換句話講就是你怎麼將原問題分解成多個子問題。
2.遞迴的定義最優解的值。就是你怎樣將多個子問題的結果合併成為原問題的解,得到最優值。
3.計算最優解。就是你採用什麼方法來計算最優解。有自上而下和自下而上,通常採用自下而上,原因後面講。
4.利用計算出的資訊構造乙個最優解。就是求解得到最優值對應的因變數。
下面舉四個例子來具體分析:
具體問題如下:
serling公司購買長鋼條,將其切割為短鋼條**,切割工序本身沒有成本支出。公司管理層希望知道最佳切割方案。鋼條長度與**關係如下:
按照動態規劃的步驟:
1.找到最優子結構
假設在長度為k處進行切割,可以得到最優解。我們就可以將原問題長度為[1,n]的鋼條最優解問題分解為長度[1,k],[k,n]的鋼條切割的子問題。
2遞迴定義最優解的值
對於兩個子問題,可以假定長度[1,k]的鋼條不再切割,而[k,n]的鋼條在進行切割,這樣我們就可以將收益公式寫出:
r(n)=max(pi+r(n-i))(1
3.計算最優解
計算最優解有兩種方法,一種是自上而下,一種是自下而上,兩種實現方法的時間複雜度都為多項式級別的,但是自上而下演算法可能沒有遞迴到所有的可能,而自下而上的演算法比較好理解,而且時間複雜度通常有更小的係數。下面具體講一下兩個方法:
自上而下:採用倒推的方式,我們想知道長度為[1,n]的最優解就必須知道底層[k,n](這裡僅僅說明一下,k為切割點)的最優解,相應的我們要知道[k,n]的最優解,就必須知道下一底層的最優解,最後推到最下層結構時,所有的最優解就都出來了。
自下而上:該方法是先算底層的最優解,由底層的最優解推到上層資料的最優解,最終得到長度為[1,n]的最優解。
最後實現的c**如下:
#include"stdio.h"
#define length 10
int memoized_cut_rod(int *p,int n);
int bottom_down_cut_rod(int *p,int n,int *r);
int max(int a,int b);
int bottom_down_cut_rod(int *p,int n);
int result;
void main()
; printf("%d\n",memoized_cut_rod(p,length));
printf("%d\n",bottom_down_cut_rod(p,length));
printf("%d",result+1);
getchar();
}int memoized_cut_rod(int *p,int n) //自上而下
if(n==0) //不加該條件會導致溢位
else
else }
int bottom_down_cut_rod(int *p,int n) //自下而上
/*q=max(q,p[j]+r[i-j-1]);
if(q==p[j]+r[i-j-1])*/
} r[i]=q;
} return r[n];
}
動態規劃 鋼條切割問題
已知鋼條切割的不同長度對應的不同 如下所示 長度i 1 23 45 67 89 10 pi 1589101717202430 求輸入長度,輸出最佳的收益。詳細理論知識見 演算法導論第十五章 p359 書中給出三個演算法 一 自頂向下遞迴實現 缺點 當n足夠大時,時間會 性地增長。偽 cut rod ...
動態規劃 鋼條切割問題
動態規劃與分治法相似,都是通過組合子問題的解來求解原問題。回顧下分治法的原理 它將問題劃分為互不相交的子問題 注意 互不相交 遞迴求解子問題,再將它們的解組合起來,即為原問題的解。但是,動態規劃與分治法不同,有以下幾點 1 對於子問題重疊的情況,分治法則重複求解,不高效。而動態規劃對每個子問題只求解...
動態規劃 鋼條切割問題
一家公司購買長鋼條,將其切割成短鋼條 切割本身沒有成本,長度為i的短鋼條的 為pi。那給定一段長度為n的鋼條和乙個 表pi,求鋼條的切割方案使得收益rn最大。如乙個pi如下 長度i123 4567 8910 pi15 891017 1720 2430 在距離鋼條左端i長度處,我們總是可以選擇切割或者...