- C24yechenxi's blog
【算法】DP
- @ 2025-4-2 17:31:11
Q:dp就是记忆化搜索吗?
A:
DP(动态规划)和记忆化搜索有一定的联系,但它们并不完全相同。
相同点
- 核心思想一致:它们都利用了“相同参>数答案相同的特性”,通过记录已计算的结果>来避免重复计算,从而优化时间复杂度。
- 可以相互转换:在很多情况下,记忆化搜索可以转化为动态规划,反之亦然。
不同点
- 实现方式:
- 动态规划:通常是自底向上的迭代方式,通过填表的方式逐步求解。
- 记忆化搜索:基于递归实现,通过在搜索过程中记录已计算的结果来避免重复计算。
- 适用场景:
- 动态规划:适用于具有重叠子问题和最优子结构特性的问题,且通常需要明确的状态转移方程。
- 记忆化搜索:适用于递归搜索过程中存在大量重复计算的情况,尤其在问题的递归结构较为复杂时更为方便。
- 效率:在某些情况下,记忆化搜索可能比动态规划更高效,因为它只计算“有价值的点”,而动态规划可能会计算一些不必要的状态。
总结
记忆化搜索可以看作是动态规划的一种实现方式,但它们在实现方式、适用场景和效率上有所不同。不能简单地说DP就是记忆化搜索,但它们在很多情况下是相通的。
Note
分组背包:
f[i][j] = max(f[i-1][j], f[i-1][j-v[i]] + w[i]);
//分组背包
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
int f[N][N]; //状态定义数组 初始值因为全局都是0了
int v[N], w[N]; //用来接收每个物品的体积和价值
int n, m, a, b; //表示物品个数 背包体积 a是物品i的体积 b是价值
int main(){
cin >> n >> m;
for(int i = 1; i <= n; ++i){
cin >> v[i] >> w[i];
}
/*
01背包的二维状态转移方程
不选 f[i][j] = f[i-1][j];
选(在体积够的情况下) f[i][j] = f[i-1][j-v[i]] + w[i];
f[i][j] = max(f[i-1][j], f[i-1][j-v[i]] + w[i])
*/
//物品从1开始 0个物品价值为0
for(int i = 1; i <= n; ++i)
//因为要保证背包容量是大于物品i的体积 所以体积直接从物品容量开始枚举
for(int j = 0; j <= m; ++j){
//不选
f[i][j] = f[i-1][j];
if(j >= v[i])f[i][j] = max(f[i][j], f[i-1][j-v[i]] + w[i]);
}
cout << f[n][m] << endl;
system("pause");
return 0;
}
区间DP
区间dp:就是对于区间的一种动态规划,对于某个区间,它的合并方式可能有很多种,我们需要去枚举所有的方式,通常是去枚举区间的分割点,找到最优的方式(一般是找最少消耗)。
例如:对于区间【i,j】,它的合并方式有很多种,可以是【i,i+1】和【i+2,j】也可以是【i,k】和【k+1,j】(其中i <= k < j)……