多重背包问题是0-1背包问题和完全背包问题的综合体,可以描述如下:从n种物品向容积为V的背包装入,其中每种物品的体积为w,价值为v,数量为k,问装入的最大价值总和?
我们知道0-1背包问题是背包问题的基础,所以在解决多重背包问题的时候,要将多重背包向0-1背包上进行转换。在多重背包问题中,每种物品有k个,可以将每种物品看作k种,这样就可以使用0-1背包的算法。但是,这样会增加数据的规模。因为该算法的时间复杂度为O(V*∑ni=1ki),所以要降低每种物品的数量ki。
九度教程上给出了一种方法,将原数量为k的物品拆分成若干组,每一组可看成一件新的物品,其价值和重量为改组中所有物品的价值重量的总和,每组物品包含的原物品个数分别为:1、2、4...k-2^c+1,其中c为使k-2^c+1大于0的最大整数。这样就将物品数量大大降低,同时通过对这些若干个原物品组合得到的新物品的不同组合,可以得到0到k之间的任意件物品的价值重量和,所以对所有这些新物品做0-1背包,即可得到多重背包的解。转化之后的时间复杂度为O(V*∑ni=1log2(ki))。
九度教程上的一道例题-珍惜现在,感恩生活
题目描述:
为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。请问:你用有限的资金最多能采购多少公斤粮食呢?
输入:
输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。
输出:
对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。
样例输入:
1
8 2
2 100 4
4 100 2
样例输出:
400
编码实现:
#include <stdio.h> struct Rice{ int price; int weight; }rice[2001]; int max(int a, int b) { return a > b ? a : b; } int dp_Rice[101]; int main() { int nCase; scanf("%d", &nCase); while (nCase--) { int sumMoney, speRice; scanf("%d%d", &sumMoney, &speRice); int index = 0; int pr, wei, num; for (int i = 1; i <= speRice; i++) { scanf("%d%d%d", &pr, &wei, &num); int k = 1; while (num - k>0) { num -= k; rice[++index].price = pr*k; rice[index].weight = wei*k; k *= 2; } rice[++index].weight = wei*num; rice[index].price = pr*num; } for (int j = 0; j <= sumMoney; j++) dp_Rice[j] = 0; for (int i = 1; i <= index;i++) for (int j = sumMoney; j >= rice[i].price; j--) dp_Rice[j] = max(dp_Rice[j],dp_Rice[j-rice[i].price]+rice[i].weight); printf("%d\n",dp_Rice[sumMoney]); } return 0; } /************************************************************** Problem: 1455 User: 凌月明心 Language: C++ Result: Accepted Time:10 ms Memory:1036 kb ****************************************************************/
写代码是一种艺术,甚于蒙娜丽莎的微笑。