多重背包 (1086 51nod)

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

输入示例

3 6
2 2 5
3 3 8
1 4 1

输出示例

9


分析:本题是多重背包问题,我们显然可以把每种物品的每一件都作为一个新的物品按照普通0-1背包的方法做。
但是0-1背包的时间复杂度是O(W * N) , 这里N = C1 + C2 + …+ Cn。

       如果用dp[i][j]表示前i件物品,总重量为j的时候的最大价值。那么dp[i][j] = max{dp[i – 1][j – k * Wi] + k * Vi},其中 0 ≤ k ≤ min( j / Wi , Ci),这个的时间复杂度是n * W * max(Ci)。

      其实我们还是应该将问题转化为0-1背包的方法解决,利用二进制的方法。每个数都可以拆分为2的次方,这样通过将数量进行2的次方拆分,得到新的重量和价值的物品。

二进制思想:

任何整数都可以表示为多个二进制数相加。 
假如说现在某种物品有三件,那么dp的时候,要算三次,分别为:放一件的时候,放两件的时候,放三件的时候,,,要三次循环,何不知,在放两件的时候,可能出现第一件已经放入的情况了,这时候其实是放了三件,等到三个一起放的时候,可能出现已经放过一件或两件或三件了。。所以一定要用二进制方法 
定理:一个正整数n可以被分解成1,2,4,…,2^(k-1),n-2^k+1(k是满足n-2^k+1>0的最大整数)的形式,且1~n之内的所有整数均可以唯一表示成1,2,4,…,2^(k-1),n-2^k+1中某几个数的和的形式。

样例:

       2 2 5
       3 3 8
      1 4 1
转化成01后:
       2 2
       4 4
       4 4
       3 3
       6 6
       12 12
       3 3
       1 4
 
代码:
      
#include<iostream>
#include<cstdio>
#include<cstring>
#define Max(a,b)a>b?a:b
using namespace std;
int dp[50005];
int weigth[1005],value[1005];
int main()
{
	int n,v;
	scanf("%d%d",&n,&v);
	int sum=0;
	int x,y,z;
	for(int i=0;i<n;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		int temp=1;
		while(z>0)
		{
			if(z>=temp)
			{
				weigth[++sum]=temp*x;
				value[sum]=temp*y;
				z=z-temp;
			}
			else
			{
				weigth[++sum]=z*x;
				value[sum]=y*z;
				z=0;
			}
			temp=temp*2;
		}
	}
	memset(dp,0,sizeof(dp));
	for(int i=1;i<=sum;i++)
	{
		for(int j=v;j>=weigth[i];j--)
		{
		//	if(j>=weigth[i])
			   dp[j]=Max(dp[j],dp[j-weigth[i]]+value[i]);
		}
	}
	printf("%d\n",dp[v]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值