看了好久好久才明白的01背包,真是来之不易
希望身为蒟蒻的我对01背包的理解能帮到你
基本模型:
有一个容积为m的背包,现在有n件重量为w[i],价值为v[i]的物品,问可装入的最大价值是多少?
我的理解和思路:
很多人想到用贪心来解决,但是如果我们按照贪心先放入价值大的得到的结果可能不如放其他几个价值没有那么大但是重量轻的。dp的思想和贪心的类似,都是求出每一个子问题的最优解,然后推及整体的最优解,但两者不同之处在于,贪心的每一次递推都是建立在上一个子问题的解就是确定的最优解的基础之上。如果接下来的一步影响到了之前子问题的最优解,那么贪心算法就无法解决问题了。而dp不同,它在由局部推及整体的时候每一次都会更新子问题的最优解。
dp的基本实现过程就是对每一件物品而言,我都有两种情况,要么取要么不取,然后我们只需要每次询问,是取之后的价值高还是不取,把最后的结果存起来,求max,再询问下一个。那么最后一步所得到的值自然就是我们所想要得到的最大值
dp方程:
当i == 0时,dp[0][j]表示把前0件物品装入j大小的背包,总价值为0,所以dp[0][j] = 0
当j == 0时,dp[i][0]表示把前i件物品装入0大小的背包,总价值为0,所以dp[i][0] = 0
当j < w[i]时,第i件物品已经无法装入,dp[i][j] = dp[i-1][j]
当j >= w[i]时,第i件物品可以装入,判断装与不装的价值大小
状态转移方程:
dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])
//二维
#include<bits/stdc++.h>
using namespace std;
int w[1010],v[1010];
int dp[1010][1010];
int m,n;
int main()
{
cin >> m >> n;
for(int i=1;i<=n;i++) cin >> w[i] >> v[i];
for(int i=1;i<=n;i++)
{
for(int k=1;k<=m;k++)
{
if(k >= w[i])
dp[i][k] = max(dp[i-1][k],dp[i-1][k-w[i]]+v[i]);
else
dp[i][k] = dp[i-1][k];
}
}
printf("%d\n",dp[n][m]);
return 0;
}
//一维
#include<bits/stdc++.h>
using namespace std;
int m,n;
int w[1005],v[1005],dp[1005];
int main()
{
cin >> m >> n;
for(int i=1;i<=n;i++) cin >> w[i] >> v[i];
for(int i=1;i<=n;i++)
{
for(int j=m;j>=w[i];j--)//倒序
{
dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
}
}
printf("%d\n",dp[m]);
return 0;
}