51nod 多重背包问题(二进制优化)

时间:2022-02-04 18:45:25

有N种物品,每种物品的数量为C1,C2......Cn。从中任选若干件放在容量为W的背包里,每种物品的体积为W1,W2......Wn(Wi为整数),与之相对应的价值为P1,P2......Pn(Pi为整数)。求背包能够容纳的最大价值。

我们可以转化成01背包来做,但是这样很慢。

所以我们可以二进制优化。

一个数a,我们可以按照二进制来分解为1 + 2 + 4 + 8 …… +2^n + 剩下的数 = a

剩下的数等于a - (1 + 2 + 4 + 8 …… +2^n )

我们把a拆成这么多项,可以证明,这么多项可以组合出1~a的每一个数

所以我们就可以把数量拆分,分成一些物品。这样会快很多。

#include<cstdio>
#include<algorithm>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;

const int MAXN = 112;
const int MAXM = 51234;
int f[MAXM], v[MAXN * 10], w[MAXN * 10];
int n, m, N;

void add(int ww, int vv, int cc) //拆分 
{
	int now = 1;
	while(1)
	{
		if(cc <= now)
		{
			w[N] = ww * cc;
			v[N++] = vv * cc;
			break;
		}
		else cc -= now;
		w[N] = ww * now;
		v[N++] = vv * now;
		now <<= 1;
	} 
}

int main()
{
	scanf("%d%d", &n, &m);
	REP(i, 0, n)
	{
		int ww, vv, cc;
		scanf("%d%d%d", &ww, &vv, &cc);
		add(ww, vv, cc);
	}
	REP(i, 0, N)
		for(int j = m; j >= w[i]; j--)
			f[j] = max(f[j], f[j - w[i]] + v[i]);
	printf("%d\n", f[m]);
	return 0;	
}