RE:StudyDiary——01背包(2020/8/28)

今天学习的是DP里面比较简单的一个问题——01背包
因为题目比较简单这里直接贴上

有 N 件物品和一个容量是 M 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

最简单的方法是用二维数组表示状态
f[i][j]表示装前i个物品总质量不大于j的最大价值
我们在选择装第i个物品时有两种选择
1.装第i个物品,则f[i][j] = f[i - 1][j - v[i]] + w[i]
2.不装第i个物品,则f[i][j] = f[i - 1][j]
于是我们可得状态方程

if(j < v[i]) //背包装不下第i个物品,我们选择不装
f[i][j] = f[i-1][j];
else .//背包可以装下第i个物品,我们要判断当前的最大价值来决定装不装
f[i][j] = max(f[i-1][j-v[i]] + w[i],f[i-1][j]);

当你了解上面的操作后,同学们就会发现,第i个物品的状态只于第i-1个物品的状态有关,所以我们可以对状态方程进行优化,优化后的方程f[j]表示总质量不大于j的最大价值
核心代码如下

	for(int i = 1;i <= n;i ++)
		for(int j = m;j >= v[i];j --)
			f[j] = max(f[j],f[j - v[i]] + w[i]);

我们可以发现,关于j的循环我们是从大到小进行的,这是为了保证我们更新最大价值的时候状态一定是从i-1个物品取得的(不明白为什么取i-1的请仔细看上面)
举一个很简单的例子,如果我们从小到大循环,我们可能会出现下面的情况,我们先对f[20]进行了最大价值的更新(此时f[20]是处于装了第i个物品的状态),然后对f[23]进行更新,f[23]的更新是从f[20] + w[i](假设第i个物品质量为3)处取得的,这样我们更新的f[23]并非从第i-1个物品的状态取得,而是第i个物品(相当于装了两个第i个物品)

最后贴一下AC的代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int maxn = 1010;
int n,m;
int f[maxn];
int v[maxn],w[maxn];

int main()
{
	cin >> n >> m;
	for(int i = 1;i <= n;i ++) cin>> v[i] >> w[i];
	for(int i = 1;i <= n;i ++)
		for(int j = m;j >= v[i];j --)
			f[j] = max(f[j],f[j - v[i]] + w[i]);
	cout << f[m];
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值