動態規劃 -- 01揹包問題
阿新 • • 發佈:2022-05-31
樸素解法 -- 二維陣列
初始化
因為f[N][N]定義在堆中,會自動初始化為零。此時算出揹包容量為M的時候的最大值,未必是全部裝滿的最大值,揹包中可能會有剩餘。若想算出正好裝滿的,需要對初始化做改動:將f[N][0]複製為零,其餘的賦值為負無窮,這樣在狀態轉移的時候可以保證所有可以作為更改的項全部都由f[N][0]轉移過來。
狀態轉移方程
f[i][j] 的狀態表示在有i個物體、j個揹包體積的情況下所選最優解。該狀態由f[i-1]推出。從f[i-1]到f[i]有兩種選擇情景,分別為選擇f[i]與不選擇f[i]。
選擇f[i] : f[i][j] = f[i - 1][j - wei[i]] + val[i] ;
不選擇f[i] : f[i][j] = f[i - 1][j];
#include <bits/stdc++.h> using namespace std; const int N = 1010; int f[N][N]; int n, m; int wei[N]; int val[N]; int main () { cin >> n >> m; for(int i = 1; i<= n ; i++) cin >> wei[i] >> val[i]; for(int i = 1; i<= n ; i++) { for(int j = 0; j<=m ; j++) { f[i][j] = f[i-1][j]; if( j >= wei[i]) f[i][j] = max(f[i][j] , f[i-1][j - wei[i]] + val[i]); } } cout << f[n][m]; return 0; }
優化 : 二維陣列變為一維陣列
針對選擇f[i]的情況 : f[i][j] = f[i - 1][j - wei[i]] + val[i] ; 變為一維陣列之後 : f[j] = f[j - wei[i]] + val[i]; 此時要保證使用的f[j - wei[i]]是在f[i-1]中算出的資料,但是如果保持原迴圈 j from 0 to m 的順序,則所用f[j - wei[i]] 則是f[i]中算出的資料,所以迴圈改為 j from m to wei[i] (如果剩餘重量不足以裝下 i 物體的話,則不需要運算)
#include <bits/stdc++.h> using namespace std; const int N = 1010; int n, m; int f[N]; int wei[N]; int val[N]; int main () { cin >> n >> m; for(int i = 1; i<= n ; i++) cin >> wei[i] >> val[i]; for(int i = 1 ; i <= n; i++) { for(int j = m ; j >= wei[i] ; j-- ) { f[j] = max(f[j] , f[j - wei[i]] + val [i]); } } cout << f[m]; return 0; }