1. 程式人生 > >DP動態規劃與記憶化搜尋的聯絡與區別

DP動態規劃與記憶化搜尋的聯絡與區別

之前遇到好幾個不會做的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更容易想到呢尷尬