之前遇到好几个不会做的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更容易想到呢