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;
}