用遞迴求解問題時,反覆的巢狀會浪費記憶體。而且更重要的一點是,之前計算的結果無法有效儲存,下一次碰到同乙個問題時還需要再計算一次。例如遞迴求解 fibonacci 數列,假設求第 n 位(從 1 開始)的值,c **如下:
#include
intfib
(int n)
return
fib(n -1)
+fib
(n -2)
;}intmain
(void
)
上面的**,每個運算節點都需要拆成兩步運算,時間複雜度位 o(2^n)。
你可以把 n 改為 40 左右試試,這是消耗的時間就是秒級了。總共的求解步驟如下:
求第 2 位
求第 3 位
如果想把每次求解的結果儲存下來,就需要乙個長度位 n 的陣列,從頭開始把每乙個位置的值儲存下來,這樣求解後面的值的時候就可以用了。
對於遞迴,只要寫好了退出條件,之後不停的呼叫自身即可,最終到達退出條件時,逐個退出函式。
動態規劃則是從頭開始,用迴圈達到目的。
動態規劃和遞迴的最大的區別,就是在碰到重疊子問題(overlap sub-problem)時,是否只需要計算一次。
#include
intfib
(int n)
return dp_opt[n -1]
;}intmain
(void
)
上面**的時間複雜的是 o(n)。
題目:從集合中,任取任意多個非相鄰的數字並求和,找出最大的和。例如,對於 ,最大的和是 14。
分析:對於任意第 n 位數字,都有兩種情況,只需要取值最大的那種即可:
遞迴退出條件:
遞迴迴圈:
int
recursive
(int arr,
int n,
int i)
為了確保每個最小子問題都只計算一次,就必須把計算的結果儲存起來。另外,跟遞迴的逆序求解方向相反,動態規劃從第乙個元素開始,依次計算每個元素的最大和:
int
dp_opt
(int arr,
int n,
int x)
opt[0]
= arr[0]
; opt[1]
= arr[0]
> arr[1]
? arr[0]
: arr[1]
;for
(i =
2; i < n; i++
)return opt[x]
;}
#include
// 遞迴解法
intrecursive
(int arr,
int n,
int i)
// 動態規劃
intdp_opt
(int arr,
int n,
int x)
opt[0]
= arr[0]
; opt[1]
= arr[0]
> arr[1]
? arr[0]
: arr[1]
;for
(i =
2; i < n; i++
)return opt[x];}
intmain()
;for
(i =
0; i <
7; i++
)return0;
}
例如,對於 ,給定值位 15,則可以找到組合 滿足條件。
要判斷多個元素之和是否等於某個值 sum,則對於任意的元素 n,情況如下:
遞迴退出條件:
遞迴迴圈:
int
recursive
(int arr,
int n,
int sum)
有了上面的遞迴的思路後,再把遞迴轉為動態規劃。
初始化二維陣列
上乙個例子中,求非相鄰元素最大和時,每個元素的位置上只需要儲存當前元素的最大值,所以建立乙個一維陣列即可。而現在已知元素之和,
例如,對於集合 ,如果 sum = 6,則需要建立 dp_subset[5][7] 陣列:
arr[i]
i \ sum01
2345
630f
fftf
ff50
t90t
10t2
0t開始迭代
在已經初始化的二維陣列基礎上,參考遞迴體就可以完成迭代的**。另外,還有乙個遞迴結束條件也放在迭代裡面。
int
dp_subset
(int arr,
int n,
#include
// 遞迴解法
intrecursive
(int arr,
int n,
int sum)
// 動態規劃
intdp_subset
(int arr,
int n,
int sum)
for(i =
0; i < n; i++
) subset[0]
[0]=
0;subset[0]
[arr[0]
]=1;
for(i =
1; i < n; i++
)else}}
return subset[n -1]
[sum];}
intmain()
;int sum =3;
printf
("recursive ret is: %d, dp_opt ret is: %d\n"
,recursive
(arr, n, sum)
,dp_subset
(arr, n, sum));
return0;
}
演算法與資料結構 動態規劃
動態規劃 dp 的基本思想是 當前子問題的解可由上一子問題的解得出。動態規劃演算法通常基於由乙個遞推公式 狀態轉移方程 和若干個初始狀態 狀態 應用 1 lis longest increasing subsequence 求乙個陣列中的最長非降子串行的長度。子問題 我們可以考慮先求a 0 a 1 ...
資料結構與演算法練習 動態規劃
hz偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了 在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題很好解決。但是,如果向量中包含負數,是否應該包含某個負數,並期望旁邊的正數會彌補它呢?例如 連續子向量的最大和為8 從第0個開始,到第...
資料結構與演算法 156 159 動態規劃
揹包問題 有乙個揹包,容量為4磅,物品重量 吉他 g 11500 音響 s 43000 電腦 l 32000 動態規劃演算法介紹 動態規劃演算法最佳實踐 揹包問題 物品重量 吉他 g 11500 音響 s 43000 電腦 l 32000 思路和 v i 0 0 j 0 當 w i j時 v i j...