動態規劃

動態規劃過程:每次決策依賴於當前狀態,又隨即引起狀態的轉移。
一個決策序列就是在變化的狀態中產生出來的,所以,這樣的多階段最優化決策解決這個問題的過程就稱爲動態規劃。
動態規劃是運籌學中用於求解決策過程中的最優化數學方法。

假設問題是由交疊的子問題所構成,我們就能夠用動態規劃技術來解決。一般來說,這種子問題對給定問題求解的遞推關係,這個遞推關係包括了同樣問題的更小子問題的解。動態規劃法建議,與其對交疊子問題一次重新的求解,不如把每個較小子問題僅僅求解一次,並把結果記錄在表中(動態規劃也是空間換時間)。這樣就能夠從表中得到原始問題的解。
動態規劃經常使用於解決最優化問題,這些問題多表現爲多階段決策。
關於多階段決策:
在實際中,人們經常遇到這樣一類決策問題:即因爲過程的特殊性,能夠將決策的全過程根據時間或空間劃分若干個聯繫的階段。
而在各階段中,都要作出決策,當一個階段作出決策後,經常影響到下一個階段的決策,從而影響整個過程的活動。這樣,各個階段所確定的決策就構成一個決策序列,常稱之爲策略。因爲各個階段可供選擇的決策往往不止一個。因而就可能有很多決策以供選擇,這些可供選擇的策略構成一個集合,我們稱之爲同意策略集合(簡稱策略集合)。每一個策略都對應地確定一種活動的效果。我們假定這個效果能夠用數量來衡量。
因爲不同的策略經常導致不同的效果,因此,怎樣在同意策略集合中選擇一個策略,使其在預定的標準下達到最好的效果。

案例一(一維):
有n級臺階,一個人每次上一級或者兩級,穩有多少種走完n級臺階的方法。
分析:動態規劃的實現的關鍵在於能不能準確合理地用動態規劃表來抽象出實際問題。這個問題我們讓f(n)表示走上n級臺階的方法數。
那麼當n爲1時,f(n) = 1,當n = 2, f(n) = 2,就是說當臺階只有一級的時候,方法數是一種,臺階有兩級的時候,方法數爲2。那麼當我們要走上n級臺階的方法數必然是n-1級臺階的方法數加上n -2級臺階的方法數之和。即f(n) = f(n - 1) + f(n - 2),我們用dp[n]來表示動態規劃表,dp[i], i > 0, i <= n,表示到達i級臺階的方法數。

//dp是全局數組,大小爲n,全部初始化爲0
int *dp = new int [n];
int fun(int n){
	if (n == 1 || n == 2)
		return n;
	if (!dp[n - 1])
		return dp[n - 1] = fun(n - 1);
	if (!dp[n - 2])
		return dp[n - 2] = fun(n - 2);
	return dp[n - 1] + dp[n - 2];
}

案例二(二維):
給定一個矩陣m,從左上角開始每次只能向右走或者向下走,最後達到右下角的位置,路徑中所有數字累加起來就是路徑和,返回所有路徑的最小路徑和,如果給定的m如下,那麼路徑1,3,1,0,6,1,0就是最小路徑和,返回12。
1 3 5 9

8 1 3 4

5 0 6 1

8 8 4 0

分析:對於這個題目,假設m是m行n列的矩陣,那麼我們用dp[m][n]來抽象這個問題,dp[i][j]表示的是從原點到i,j位置的最短路徑和,要麼是從上邊的位置達到,我們取左邊和上邊的較小值,然後加上當前的路徑值,就是達到當前點的最短路徑。然後從左到右,從上到下依次計算即可。

#include<iostream>
#include<algorithm>
using namespace std;
int dp[4][4] = {};
int main(){
	int arr[4][4] = {1,3,5,9,8,1,3,4,5,0,6,1,8,8,4,0};
	const int oo = ~0U>>2;//INT_MAX
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			dp[i][j] = oo;
	for (int i = 0; i < 4; i++){
		for (int j = 0; j < 4; j++){
			if (dp[i][j] == oo){
				if (i == 0 && j == 0)
					dp[i][j] = arr[i][j];
				else if (i == 0 && j != 0)
					dp[i][j] = arr[i][j] + dp[i][j - 1];
				else if (i != 0 && j == 0)
					dp[i][j] = arr[i][j] + dp[i - 1][j];
				else{
					dp[i][j] = arr[i][j] + min(dp[i - 1][j], dp[i][j - 1]);
				}
			}
		}
	}
	for (int i = 0; i < 4; i++){
		for (int j = 0; j < 4; j++){
			cout<<dp[i][j]<<"    ";
		}
		cout<<endl;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章