悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 hdu2191 多重背包

http://acm.hdu.edu.cn/showproblem.php?pid=2191

这是个典型的多重背包,给了总钱数, 每种大米的价格、重量、袋数。求能够购买的最大重量。

这个是从别的地方copy来的简单背包问题的讲解:

先说下 01 背包,有n 种不同的物品,每个物品有两个属性  size 体积,value 价值,现在给一个容量为 w 的背包,问最多可带走多少价值的物品。  
  
    int f[w+1];   //f[x] 表示背包容量为x 时的最大价值  
    for (int i=0; i<n; i++)  
        for (int j=w; j>=size[i]; j--)  
            f[j] = max(f[j], f[j-size[i]]+value[i]);  
  
    如果物品不计件数,就是每个物品不只一件的话,稍微改下即可  
    for (int i=0; i<n; i++)  
        for (int j=size[i]; j<=w; j++)  
            f[j] = max(f[j], f[j-size[i]]+value[i]);  
  
    f[w] 即为所求  
  
    初始化分两种情况  
    1、如果背包要求正好装满则初始化 f[0] = 0, f[1~w] = -INF;  
    2、如果不需要正好装满 f[0~v] = 0;  
  
    多重背包问题要求很简单,就是每件物品给出确定的件数,求可得到的最大价值  
    多重背包转换成 01 背包问题就是多了个初始化,把它的件数C 用分解成若干个件数的集合,这里面数字可以组合成任意小于等于C的件数,而且不会重复,之所以叫二进制分解,是因为这样分解可以用数字的二进制形式来解释。
    比如:7的二进制 7 = 111 它可以分解成 001 010 100 这三个数可以组合成任意小于等于7 的数,而且每种组合都会得到不同的数
    15 = 1111 可分解成 0001  0010  0100  1000 四个数字  
    如果13 = 1101 则分解为 0001 0010 0100 0110 前三个数字可以组合成7以内任意一个数,加上 0110 = 6 可以组合成任意一个大于6 小于13 的数,虽然有重复但总是能把13 以内所有的数都考虑到了,基于这种 思想去把多件物品转换为,多种一件物品,就可用01 背包求解了。  
  
    看代码:  
    int n;  //输入有多少种物品  
    int c;  //每种物品有多少件  
    int v;  //每种物品的价值  
    int s;  //每种物品的尺寸  
    int count = 0; //分解后可得到多少种物品  
    int value[MAX]; //用来保存分解后的物品价值  
    int size[MAX];  //用来保存分解后物品体积  
  
    scanf("%d", &n);    //先输入有多少种物品,接下来对每种物品进行分解  
  
    while (n--) {   //接下来输入n中这个物品  
        scanf("%d%d%d", &c, &s, &v);  //输入每种物品的数目和价值  
        for (int k=1; k<=c; k<<=1) { //<<右移 相当于乘二  
            value[count] = k*v;  
            size[count++] = k*s;  
            c -= k;  
        }  
        if (c > 0) {  
            value[count] = c*v;  
            size[count++] = c*s;  
        }  
    }  
  
    现在用count 代替 n 就和01 背包问题完全一样了  

#include <iostream>
using namespace std;
#define NSORT 25*25
#define NWEIGHT 105
int value[NSORT],weight[NSORT],sum[NWEIGHT];

int max(int a,int b){
	return a>=b?a:b;
}

int main(){
	int t,volume,n,i,j;
	int count,p,h,c,k;
	scanf("%d",&t);
	while (t--){
		scanf("%d%d",&volume,&n);
		count=1;
		for (i=1;i<=n;i++){
			scanf("%d%d%d",&p,&h,&c);
			for (k=1;k<=c;k=k<<1){
				value[count]=k*p;
				weight[count]=k*h;
				c=c-k;
				count++;
			}
			if (c>0){
				value[count]=c*p;
				weight[count]=c*h;
				count++; //这里的count++不能丢掉哦。
			}
		}
		memset(sum,0,sizeof(sum));
		count--;
		for (i=1;i<=count;i++)
			for (j=volume;j>=value[i];j--)
				sum[j]=max(sum[j],sum[j-value[i]]+weight[i]);
		printf("%d\n",sum[volume]);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值