数据结构与算法(C++)– 动态规划(Dynamic Programming)
生活随笔
收集整理的這篇文章主要介紹了
数据结构与算法(C++)– 动态规划(Dynamic Programming)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
動態規劃(Dynamic Programming)
理解動態規劃的好文:https://www.sohu.com/a/153858619_466939
1、基礎
**定義:**遞歸算法經常會有一些重復的計算,導致程序效率低。動態規劃就是解決這個問題的方法。
動態規劃的組成部分:
- 最優子結構:分解問題
- 邊界:遞歸的終止條件
- 狀態轉移方程:遞歸的方程
動態規劃的解題步驟:
- 分解問題,得到狀態轉移方程
- 暴力搜索,找到冗余,通常用純遞歸
- 存儲已經計算過的結果,通常用數組和字典
- 編程時通常采用自底向上思想(遞推)
2、走臺階問題
**題目:**有一座10級臺階的樓梯,從下往上走,每跨一步只能向上1級或者2級臺階。要求用程序來求出一共有多少種走法。
遞歸解法:
int solve(int n) {if(n < 1)return 0;if(n == 1)return 1;if(n == 2)return 2;return solve(n-1)+solve(n-2); }備忘錄解法:
int solve(int n,HashMap<Interger, Interger>map) {if(n < 1)return 0;if(n == 1)return 1;if(n == 2)return 2;if(map.contains(n))return map.get(n);else{int value = solve(n-1)+solve(n-2);map.put(n, value);return value;} }動態規劃解法:
int solve(int n,HashMap<Interger, Interger>map) {if(n < 1)return 0;if(n == 1)return 1;if(n == 2)return 2;int a = 1;int b = 2:int temp = 0;for(int i=3; i<=n; i++){temp = a + b;a = b;b = temp;}return temp; }題目改為一次最多能走k階臺階
思路:其實是一樣的,只要把邊界和遞歸式擴展到 k 即可
// 邊界條件, 轉化為總共 k 階臺階,可以任意走,到達k階有2^(k-1)種走法 num[0] = 1 for(int i=1; i =< k; ++i)num[i] = power(2, i-1);// 遞推 for(int j = k+1; j<n+1; ++j) {z = 1;while(z < k){num[j] += num[j-z];z += 1;} }3、打家劫舍問題
**題目:**偷商店,不能連續偷兩家,求偷的總額最大
備忘錄解法:
vector<int> save; int solve(vector<int>& nums, int n) {if(n < 0)return 0;if(save[n] >= 0)return save[n];save[n] = max(solve(nums, n-2)+nums[n], solve(nums, n-1));return save[n]; } int rob(vector<int>& nums) {int len = nums.size();for(int i=0; i<len; i++)save.push_back(-1);return solve(nums, len-1); }動態規劃解法:
int rob(vector<int>& nums) {int n = nums.size(); if(n == 0)return 0;if(n == 1)return nums[0];vector<int> save(n, -1);save[0] = nums[0];save[1] = max(nums[0], nums[1]);for(int i=2; i<n; ++i)save[i] = max(nums[i]+save[i-2], save[i-1]);return save[n-1];4、01背包問題
題目: 給定 n 種物品和一個容量為 C 的背包,物品 i 的重量是 wi,其價值為 vi ,應該如何選擇裝入背包的物品,使得裝入背包中的物品的總價值最大?
// 下標為0的元素,沒有用到,置為0 int v[N]={0,8,10,6,3,7,2}; int w[N]={0,4,6,2,2,5,1}; int n=6,c=12;int solve() {// 需要知道的初始值是 m[i][0],m[0][j] 都等于0,所以數組都初始化為0int m[n+1][c+1] = {0};for(int i=1;i<=n;i++){for(int j=1;j<=c;j++){if(j>=w[i])m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i]); elsem[i][j]=m[i-1][j];}}return m[n][c]可以進一步壓縮空間,只用2x(c+1)或1x(c+1)大小的數組:
# 2x(c+1)數組 int m[2][c+1] = {0}; m[i%2][j]=max(m[(i-1)%2][j],m[(i-1)%2][j-w[i]]+v[i]); # 1x(c+1)大小的數組 int m[c+1] = {0}; m[j]=max(m[j],m[j-w[i]]+v[i]);5、硬幣找零
題目: 硬幣的種類值列表 coin_list,要找零錢 change 元,問最少需要幾個硬幣?
遞歸解法:
def find_coins(coin_list, change):min_coins = changeif change in coin_list:return 1else:for i in [c for c in coin_list if c <= change]:num_coins = 1 + find_coins(coin_list, change-i)if num_coins < min_coins:min_coins = num_coinsreturn min_coinsprint(recDC([1,5,10,25], 63)備忘錄解法:
# save_list 緩存已經算過的零錢最少找幣數,列表大小=最初需要找零的值+1,初始值都=0 def find_coins(coin_list, change, save_list):min_coins = changeif change in coin_list:return 1elif save_list[change] > 0:return save_list[change]else:for i in [c for c in coin_list if c <= change]:num_coins = 1 + find_coins(coin_list, change-i, save_list)if num_coins < min_coins:min_coins = num_coinssave_list[change] = min_coinsreturn min_coinsprint(recDC([1,5,10,25], 63, [0]*64))動態規劃解法:
# 遞推 def find_coins(coins_list, change, min_coins_list):for num in range(change+1):num_coins = numfor j in [c for c in coins_list if c <= num]:if min_coins_list[num-j] + 1 <= num_coins:num_coins = min_coins_list[num-j]+1min_coins_list[num] = num_coinsreturn min_coins_list[change]print(find_coins([1, 5, 10, 25], 63, [0]*64))GOOD LUCK!
總結
以上是生活随笔為你收集整理的数据结构与算法(C++)– 动态规划(Dynamic Programming)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java+的数组分割符_Java:使用分
- 下一篇: 红黑树 —— 原理和算法详细介绍