动态规划的典型套路:求最大值、最优解、最大、最小、最长、计数等问题。
01背包问题描述:从 M 件物品中取出若干件放入容量为 W 的背包,每件物品的体积为 W1、W2……Wn,对应价值为 P1、P2……Pn,求能装入背包的最大总价值。
暴力递归求解
最直接的思路是用递归枚举"拿"与"不拿"两种选择:
int w[10] = { 1, 4, 3, 0, 0, 0, 0, 0, 0 };
int v[10] = { 4, 6, 3, 0, 0, 0, 0, 0, 0 };
//0 5
int f(int x, int W)
{
if (W < w[x])return f(x + 1, W);//剩余可用重量 小于当前物体重量
if (W <= 0)return 0;//剩余重量 返回价值0
if (x >= 4)return 0;
int ret = max(f(x + 1, W - w[x]) + v[x], f(x + 1, W));// 拿和不拿
return ret;
}
DP 表格递推
递归存在大量重复计算,可以用二维数组缓存已计算的结果。递归中重量依次递减、物品 index 从大到小,因此 DP 循环顺序如下:
for (int xx = num - 1; xx >= 0; xx--)
{
for (int ww = 0; ww <= MAX; ww++)
{
if (ww < w[xx])
{
arr[xx][ww] = arr[xx + 1][ww];
}
else
{
int a = arr[xx + 1][ww - w[xx]] + v[xx];//拿
int b = arr[xx + 1][ww];// 不拿
arr[xx][ww] = max(a, b);
}
}
}