多重背包 记录

Problem Description
为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。
请问:你用有限的资金最多能采购多少公斤粮食呢?

Input
输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。

Output
对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。

Sample Input
1
8 2
2 100 4
4 100 2

Sample Output
400

思路:多重背包转为01背包,通过将物品数量拆分进行二进制优化
例: 如10个物品的数量,分别转为1, 2, 4, 10 -(1 + 2 + 4), 做为一个物品去存储
价格 重量 数量
2 100 10 —>转为
price[0] = 2 * 2^0, weight[0] = 100 * 2^0,          剩余10 - 2^0 = 9个物品
price[1] = 2 * 2^1 = 4, weight[1] = 100 * 2^1 = 200;          剩余9 - 2^1 = 9 - 2 = 7
price[2] = 2 * 2^2 = 8, weight[2] = 100 * 2^2 = 400;          剩余7 - 2^2 = 7 - 4 = 3
因为3 < 2^3
所以price[3] = 2 * 3 = 6, weight[3] = 100 * 3 = 300;
就转为了01背包

#include<bits/stdc++.h>
using namespace std;

int c, n, m, p[200005], w[200005], price, weight, num;
int dp[1000005];

int main() {
	scanf("%d", &c);
	while(c--) {
		memset(dp, 0, sizeof(dp));
		scanf("%d %d", &n, &m);  // n: 价格, m: 种类 
		int ans, k = 0;  // k: 数组下标 
		for(int i = 0; i < m; i++) {
			scanf("%d %d %d", &price, &weight, &num);
			ans = 1;
			while(num >= ans) {
				p[k] = price * ans;
				w[k++] = weight * ans;  // 这里k++,k先赋值,再加加,确保了p和w是同一组,且更新了数组下标
				num -= ans;
				ans *= 2;
			}
			if(num) {  // 剩余数量
				p[k] = price * num;
				w[k++] = weight * num;
			}
		}
		//转为01背包 
		for(int i = 0 ; i < k; i++) { // 遍历物品种类 
			for(int j = n; j >= p[i]; j--) {  //  从后往前到当前价格为止遍历"容量" 
				dp[j] = max(dp[j], dp[j - p[i]] + w[i]);
			}
		}
		printf("%d\n", dp[n]);
	}
	return 0;
} 

//没有优化过的代码,一直wa没找到原因,觉得应该不是优化的问题,数量还是挺小的。

#include<bits/stdc++.h>
using namespace std;

int c, n, m, p[255], w[255], num[255];
int dp[1000005];

int main() {
	scanf("%d", &c);
	while(c--) {
		memset(dp, 0, sizeof(dp));
		scanf("%d %d", &n, &m);  // n: 金额, m: 种类 
		for(int i = 0; i < m; i++)	scanf("%d %d %d", &p[i], &w[i], &num[i]);
		for(int i = 0; i < m; i++) {  // 遍历每一个物品 
			for(int j = 1; j <= num[i]; j++) {  // 将从1到num[i]数量分别作为每一种物品 
				for(int k = n; k >= p[i] * j; k--) {
						dp[k] = max(dp[k], dp[k - j * p[i]] + w[i] * j);
					//printf("dp[%d] = %d\n", k, dp[k]);
				} 
			} 
		}
		printf("%d\n", dp[n]);
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值