1 问题
(此题在csdn上查找了大量资料)
多重背包问题是01背包问题和完全背包问题的改版,背包的容量为M(不超过背包时全部初始化为0,刚好装满第0容量初始化为0,其他初始化为-1,见后面代码),有n种物品,每种物品的价值为di,重量为wi,最多可以取ci件。问背包所放价值最大是多少。
通俗来讲,小黑推着购物车去超市,购物车容量一定,有n种物品,啤酒饮料矿泉水,瓜子花生八宝粥等,每种物品最多取ni件,比如矿泉水最多拿五瓶,瓜子最多拿十袋等,怎样才能使小黑的购物车种物品的价值最大。
2 O(N*C*M)解法
2.1 问题分析
多重背包问题可以退化为01背包问题来求解,有n种物品,每种物品至多有ci件,则一共可以有n*c个物品(是“个”,不是“种”),每个物品可以选择拿或者不拿,这个问题就和01背包问题一模一样。外层循环是物品个数,内层循环是背包容量(需要逆序,原因见完全背包问题解释)。
2.2 代码编写
#include <iostream>
#include <algorithm>
using namespace std;
void test(){
int N,M; //物品种类,背包容量
cin>>N>>M;
int* arrW = new int[N+1]; //物品体积数组
int* arrD = new int[N+1]; //物品价值数组
int* arrC = new int[N+1]; //每种物品的数量数组
int* arrM = new int[M+1]; //背包容量数组
for(int i = 0;i <= M;i++){
//初始化背包容量数组,若不超过背包容积则全部初始化为0,若刚好装满,则第0项初始化为0,其他均初始化为1;
arrM[i] = 0;
}
for(int i = 1;i <= N;i++){
cin>>arrW[i]>>arrD[i]>>arrC[i]; //初始化物品的体积,价值,数量
}
for(int i = 1;i <= N;i++){ //最外层循环,物品种类
for(int j = 1;j <= arrC[i];j++){ //中层循环,第i种物品的至多数量
//for(int k = M;k >= 0;k--){ //内层循环,背包的容量
// if(arrW[i] <= k){
//当作01背包问题来求解
//arrM[k] = max(arrM[k],arrM[k-arrW[i]]+arrD[i]);
// }
//}
for(int k = M;k >= arrW[i];k--){
arrM[k] = max(arrM[k],arrM[k-arrW[i]]+arrD[i]);
}
}
}
//以上是三层循环,时间复杂度为三数相乘,N*C*M
cout<<arrM[M]<<endl;
delete[] arrW;
delete[] arrD;
delete[] arrC;
delete[] arrM;
}
int main()
{
test();
return 0;
}
3 O(N*(lgC)*M)解法
3.1 问题分析
对于2中复杂度为N*C*M,如果C过大,则时间复杂度过高,很有可能会超时,对于任何一个整数,都可以用一个二进制来表示,比从1一直遍历到这个数复杂度要低很多。比如数字9,可以用1 2 5来表示,1 2 5可以组成1到9之间的任意一个数,再比如13,可以用1 2 4 6来表示,1 2 4 6(为什么不是1 2 4 8,因为1+2+4+8 > 13,随机组合数已经超过了范围)可以组合表示1到13任何一个数字,比从1直接到13复杂度降低很多。也就是lgC复杂度。
3.2 代码编写
#include <iostream>
#include <algorithm>
using namespace std;
void test(){
int N,M; //物品种类数,背包容量
cin>>N>>M;
int* arrW = new int[N+1]; //物品的体积数组
int* arrD = new int[N+1]; //物品的价值数组
int* arrC = new int[N+1]; //每种物品的个数数组
int* arrM = new int[M+1]; //背包容积数组
for(int i = 0;i <= M;i++){
arrM[i] = 0; //此为不超过情况,刚好情况初始化为0 -1 -1 -1 ...
}
for(int i = 1;i <= N;i++){
cin>>arrW[i]>>arrD[i]>>arrC[i];
}
for(int i = 1;i <= N;i++){
int tempC = arrC[i]; //把tempC当作13,举例子带入即可
for(int j = 1;tempC > 0;j = j<<1){
int mul = min(tempC,j); //mul的值为1 2 4 6
for(int k = M;k >= arrW[i]*mul;k--){ //1 2 4 6带入
arrM[k] = max(arrM[k],arrM[k-arrW[i]*mul]+arrD[i]*mul);
}
tempC = tempC - mul;
}
}
cout<<arrM[M]<<endl;
delete[] arrW;
delete[] arrD;
delete[] arrC;
delete[] arrM;
}
int main(){
test();
return 0;
}