DP動態規劃與記憶化搜尋的聯絡與區別
阿新 • • 發佈:2018-12-23
之前遇到好幾個不會做的DP題,請教小夥伴,小夥伴都是用記憶化搜尋打發我
今天閒下來認真看了看,感覺似乎理解了一些
試著寫了下LCS(最長公共子序列),程式碼如下:
#include <cstdio> #include <iostream> #include <algorithm> #define MAXN 10010 #define ll long long using namespace std; int dp[MAXN][MAXN]; string str1, str2; /*//記憶化搜尋 int LookUp(int i, int j) { if(dp[i][j]) return dp[i][j]; if(i==0 || j==0) return 0; if(str1[i-1] == str2[j-1]) { dp[i][j] = LookUp(i-1, j-1)+1; } else dp[i][j] = max(LookUp(i-1, j), LookUp(i, j-1)); return dp[i][j]; } */ int main(void) { cin >> str1 >> str2; // LookUp(str1.size(), str2.size()); for(int i=1; i<=str1.size(); ++i) { for(int j=1; j<=str2.size(); ++j) { if(str1[i] == str2[j]) dp[i][j] = dp[i-1][j-1]+1; else dp[i][j] = max(dp[i-1][j], dp[i][j-1]); } } cout << dp[str1.size()][str2.size()] << endl; return 0; }
可以注意到,原理都是相同的,只是實現方法不同
可以明顯的發現有以下幾點不同:
1、DP是從下向上,而記憶化搜尋是從上向下的
2、DP是從下向上,為了求到最終結果需要把過程中所有的值都儲存下來,以便下一步可能會使用,而因為記憶化搜尋是從上向下的,所以求解過程求的都是需要的;也就是說不需要的值並沒有求
3、記憶化搜尋使用遞迴實現的,從上面的程式碼可以看出
如果一個dp[i][j]的值已經求過,使用DP直接呼叫即可;而使用記憶化搜尋則要進入遞迴
如果一個dp[i][j]的值還未求過,使用DP直接求得,而使用記憶化搜尋則要進入遞迴中去求,而這個遞迴很有可能是多重的
這樣一來DP在時間上幾乎總是優於記憶化搜尋的
問了好幾個人都說記憶化搜尋更容易想到,但我為什麼覺得DP更容易想到呢