参考博客(可以去看看,极其详细)
https://www.cnblogs.com/kkbill/p/12081172.html
引用作者的一句话:“针对这个问题,本人理解了多次,也了看各种题解,尝试各种办法总还觉得抽象;
或者说,看了多次以后,只是把题解的状态转移方程记住了而已,并没有真正的“掌握”其背后的逻辑。”
f[i][j]代表只看前n件物品,总体积为j,最大价值
res = max(f[n][0~v])
f[i][j] :
1不选i物品,f[i][j] = f[i - 1][j]
2选i物品,f[i][j] = f[i - 1][j - v[i] + w[i]]
i号物品的价值加上减去i号物品占用的空间后剩余的背包空间所能存放的最大价值
01背包问题一般有两种不同的问法;
一种是“恰好装满背包”的最优解,要求背包必须装满,那么在初始化的时候,除了dp(0)为0,其他的dp(i)都应该设置为负无穷大.
另一种问法不要求装满,而是只希望最终得到的价值尽可能大,那么初始化的时候,应该将dp(i)全部设置为0。
#include <iostream>
#include <algorithm>
using namespace std;
int N, V;
int w[1111], v[1111], dp[1111][1111];
int main()
{
cin >> N >> V; // 物品容量&总容量
for (int i = 1; i <= N; i++)
cin >> v[i] >> w[i]; // 体积&价值
for (int i = 1; i <= N; i++) // 从1号物体开始计算,逐渐增加可选物品
{
for (int j = 1; j <= V; j++) // 从临时容量1开始计算,逐渐增加至最大容量;临时容量为0无意义,任意物体体积都不为0,无法装入
{
if (j < v[i]) // 临时容量小于此物体的体积
dp[i][j] = dp[i - 1][j]; // 相当于此件物品没被选的时候 ,结果一样
else
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - v[i]] + w[i]); // i号物品的价值加上剩余的背包空间的最大价值
// cout << dp[i][j] << " ";
}
// cout << endl;
}
cout << dp[N][V];
system("pause");
}
// 一维数组优化
#include <iostream>
#include <algorithm>
using namespace std;
int N, V;
int w[1111], v[1111], dp[1111];
int main()
{
cin >> N >> V; // 物品容量&总容量
for (int i = 1; i <= N; i++)
cin >> v[i] >> w[i]; // 体积&价值
for (int i = 1; i <= N; i++) // 从1号物体开始计算,逐渐增加可选物品
{
for (int j = V; j >= v[i]; j--) // 从最大容量开始计算,逐渐减少至v[i] 反向遍历避免覆盖小索引值出错 j<v[i] => 临时容量小于物体体积
{
dp[j] = max(dp[j], dp[j - v[i]] + w[i]); // i号物品的价值加上剩余的背包空间的最大价值
// cout << dp[i] << " ";
}
// cout << endl;
}
cout << dp[V];
system("pause");
}