01背包#dp

看了好久好久才明白的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;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你数过天上的星星吗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值