完全背包问题

有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。
i i i 种物品的体积是 v i v_i vi,价值是 w i w_i wi
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
两个整数 N , V N,V NV 用空格隔开,分别表示物品种数和背包容积。

该题与01背包的不同在于所有的物品都是无限的,即每个物品可以装多次。

朴素做法这里我们就不说了。直接给个简化的算法。

#include <iostream>
#include <cstring>
#include <algorithm>
#define MAX 1010

using namespace std;

int f[MAX];
int v[MAX], w[MAX];
int N, V;

int main()
{
	cin >> N >> V;
	for (int i = 1; i <= N; i++)
		cin >> v[i] >> w[i];

	for (int i = 1; i <= N; i++)
		for (int j = v[i]; j <= V; j++)
			f[j] = max(f[j], f[j - v[i]] + w[i]);

	
	cout << f[V] << endl;
}

细心一点,我们就注意到,这与01背包的区别就是对于 j j j 的遍历成了顺序遍历。这是为什呢?

因为我们此时的物品已经是无限个了,所以在到达第 i i i 个物品时,我们要考虑能装多少个第 i i i 个物品。而正向遍历,在考虑 f ( j ) f(j) f(j) 时,也考虑了 f ( j − v i ) f(j-v_i) f(jvi) , 而 j − v i < j j-v_i < j jvi<j ,故小于 j 的情况都考虑过了(包括 j j j)。而01背包恰好相反,它不能考虑 f ( j ) f(j) f(j) 的存在,故用反向遍历。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值