0-1背包,就是每个物品只有选或者不选两种情况,且只能选一次,普通背包就是每个物品可以有多种
今天在重新回过头研究这个问题时候发现,这两种背包问题的代码区别就在于
0-1背包在写转移方程时候要从大往小写:i=0-n,j=max-w[i] bag[j]=max( bag[j-w[i]]+v[i], bag[ j ] );
这样一来,由于是从大往小的写,所以物品每次从小的添加此物品,看是否能够比现在的大,大的话就加上赋值给当前大的重量,此时小的里面还不含此物品,那么背包就不可能把每个物品使用多次
普通背包:i=0-n,j=w[i]-max bag[j]=max( bag[j-w[i]]+v[i], bag[ j ] );
这样的话,每次循环所有的背包重量,看当前的物品是否可以加进去,那么此时一个背包就可能被使用多次了
多重背包:每个物品的数量有限
思路与完全背包中"将一种物品拆成多件物品"一样.将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为
1,2,4,...,2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。例如,如果n[i]为13,就将这种
物品分成系数分别为1,2,4,6的四件物品。
转化成01背包:
伪代码:
procedure MultiplePack(cost,weight,amount)
if cost*amount>=V
CompletePack(cost,weight)
return
integer k=1
while k<amount
ZeroOnePack(k*cost,k*weight)
amount=amount-k
k=k*2
ZeroOnePack(amount*cost,amount*weight)

1 #include <cstdio>
2 #include <cstring>
3
4 int f[100002],v[12],num[12],cost[12];
5 int total,n;
6 int max(int a,int b){ return a>b?a:b;}
7
8 void OneZeroPack(int cost,int value){
9 int i,j;
10 for(i = total;i >= cost; i--)
11 f[i] = max(f[i],f[i-cost]+value);
12
13 }
14 void completePack(int cost,int weight){
15 int i;
16 for(i = cost;i <= total; i++)
17 f[i] = max(f[i],f[i-cost]+weight);
18 }
19 void multiPack(int cost,int weight,int amount){
20 if(cost*amount >= total){
21 completePack(cost,weight);
22 return ;
23 }
24 int k = 1;
25 while(k < amount){
26 OneZeroPack(k*cost,k*weight);
27 amount -= k;
28 k*=2;
29 }
30 OneZeroPack(cost*amount,amount*weight);
31 }
32 int main(){
33 int i,j,k;
34 while(scanf("%d%d",&total,&n)!= EOF){
35 memset(f,0,sizeof(f));
36 for(i = 1;i <= n; i++){
37 scanf("%d%d",&num[i],&cost[i]);
38 v[i] = cost[i];
39 }
40 for(i = 1;i <= n; i++)
41 multiPack(cost[i],v[i],num[i]);
42 printf("%d\n",f[total]);
43 }
44 }