1. 程式人生 > >【記憶化搜尋】01揹包

【記憶化搜尋】01揹包

記憶化搜尋也是實現dp的一種,有時候可能比狀態轉移方程推過去複雜,但有時候因為是直接去搜索,反而降低了思維難度

就用01揹包來練練手(設c為容量,w為重量,v為價值)

  • 記憶化搜尋是在搜尋的基礎上,進行優化,跳過開啟相同的子樹,從而避免大量的重複計算。因為在搜尋的時候可能會再次dfs到一個已經到過的點,而這個點又會再開啟一棵很大的子樹,這樣就會進行大量的重複計算,所以如果這個點訪問完畢,我們記錄下這個點的值,再次訪問時直接返回這個值,就不要再開啟這棵子樹 if(f[i][j] > 0) return f[i][j];

對於01揹包,有選和不選兩種轉移方式
採用直接搜尋(從i=1, j=c 開始搜尋)

fij=max(dfs(i+1,j),dfs(i+1,jw[i])+v[i])
對於f(i,j) 直接去搜索f(i+1,j)和f(i + 1,j - w[i])的值,再根據選和不選加上v[i]
由於開啟dfs發生在賦值之前,賦值是逆序的,在f(i,j)確定之前,f(i+1,j)和f(i+1,j-w[i])一定已經被確定好了,這樣狀態就可以被正確地轉移

還有些邊界條件,具體看程式碼

#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std; #define debug(x) cerr << #x << "=" << x << endl; const int MAXN = 1000 + 10; int n,c,f[MAXN][MAXN],w[MAXN],v[MAXN]; int dfs(int i, int c) { if(f[i][c]) return f[i][c]; if(i == n+1) return 0; if(c >= w[i]) f[i][c] = max(dfs(i+1,c), dfs(i+1
,c-w[i]) + v[i]); else f[i][c] = dfs(i+1,c); return f[i][c]; } int main() { cin >> c >> n; for(int i=1; i<=n; i++) cin >> w[i] >> v[i]; cout << dfs(1,c); return 0; }