01背包问题是一个经典的动态规划问题,不过并不适合作为动态规划的入门训练,适合作为一个动态规划的进阶训练题。如果你在此前从未接触过动态规划,那么建议先点个收藏,在学习了动态规划的相关知识点并且做了一些简单练习后再回过头来看这篇博客学习01背包问题。(要回来看哦!)
当了解了基础知识后回过头来看01背包问题,我们会发现问题中最难理解的就是状态转移方程的逻辑(亲身经历,说多了都是泪 ),所以笔者会在下文详细解释。
好了,废话不多说了,先上题!!!
**01背包问题**
有 N 件物品和一个容量是 M 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,M,用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,M≤1000
0<vi,wi≤1000
题目其实很好理解,通俗一点讲就是:你有一个容积为M的背包,房间里有N个体积和价格分别为v1,w1;v2,w2;…;vn,wn的宝物,请问你能最多带走多少钱的宝物呢?(是不是题目一下就好理解啦?)
那么重头戏来了,上代码!!!
#include<iostream>
#include<cmath> //后面要用到max函数
using namespace std;
int v[1001], w[1001]; //v,w分别用来储存第i个物体的体积与价值,
int dp[1001][1001]; //dp[i][j]的含义:你有容积为j的背包,然后要从第1个到第j个物体中选出 背包装得下的 价值和最大的 所有物体的价值和
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) //输入
{
cin >> v[i] >> w[i];
}
for (int i = 1; i <= n; i++) //依次找出从第1个物体到第i个物体的最大价值和
{
for (int j = 0; j <= m; j++) //求从第1个物体到第i个物体的 总价值不超过背包容量j的 最大总价值
/*注意:这里求出背包容量从0到m的最大总价值是有意义的!
后面状态转移方程的递推时要用到*/
{
dp[i][j] = dp[i - 1][j]; //不选第i个物品的最大值
if (j >= v[i]) //只有j>=v[i]的情况下你才能选第i个物品,否则哪怕只选这一个物体,容量为j的背包也放不下
{
dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);
/*分析:1、dp[i - 1] [ j - v[i] ]代表:你有容积为j-v[i]的背包,然后要从第1个到第i-1个物体中选出 背包装得下的 价值和最大的 所有物体的价值和
2、因为只有找到从第1个到第i-1个、容积不超过( j - v[i]) 的背包能装下的 价值和最大的 所有物体的价值和后,把背包扩容为j
再加上第i个物体的体积v[i]才能100%保证扩容后的背包能装的下
3、最后要用max函数比较一下,看看选第i个的情况和不选第i个的情况哪个的价值和大,谁大dp[i][j]就存下谁*/
}
}
}
cout << dp[n][m]; //输出:你有容积为n的背包,然后要从第1个到第m个物体中选出 背包装得下的 价值和最大的 所有物体的价值和
return 0;
}
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例
8
到这里,笔者对01背包问题的思路就全介绍完啦,代码分析部分可能会有点乱,要是看不懂可以私信笔者哦!
作者:Avalon Demerzel,是个正在不断努力学习的小白,如果觉得博客不错,就来个三连吧(点个赞也行)。让我们一起进步。