多重背包

https://www.cnblogs.com/shuaihui520/p/9043143.html

(1)二进制的优化
这是一个多重背包的模板,也是十分好用的一种模板,因为这个比直接拆除01 背包来做
要省些时间。这是为啥呢,首先先由我讲一下为什么能换成01 背包吧。
举个例子。假如给了我们 价值为 2,但是数量却是10 的物品,我们应该把10给拆开,
要知道二进制可是能够表示任何数的,所以10 就是可以有1,2, 4,8之内的数把它组成,一开始我们选上 1了,
然后让10-1=9,再选上2,9-2=7,在选上 4,7-4=3,
而这时的3<8了,所以我们就是可以得出 10由 1,2,4,3,来组成,就是这个数量为1,2,3,4的物品了,
那么他们的价值是什么呢,是2,4,6,8,也就说给我们的价值为2,数量是10的这批货物,已经转化成了价值分别是2,4,6,8元的货物了,
每种只有一件哎!!!!这就是二进制优化的思想。
那为什么会有完全背包和01 背包的不同使用加判断呢?原因也很简单啊,当数据很大,大于背包的容纳量时,我们就是在这个物品中取上几件就是了,
取得量时不知道的,也就理解为无限的啦,这就是完全背包啦,反而小于容纳量的就是转化为01背包来处理就是了,可以大量的省时间。

c模板

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 1000         //物品个数 
#define M 100000000    //所有物品可能的最大价值 
int m[N],c[N],w[N],f[M];
int V;
int max(int a,int b){return a>b?a:b;}
void ZeroOnePack(int cost,int weight)
{
    int v;
    for(v=V;v>=cost;v--) f[v]=max(f[v],f[v-cost]+weight);
}
void CompletePack(int cost,int weight)
{
    int v;
    for(v=cost;v<=V;v++)
        f[v]=max(f[v],f[v-cost]+weight);
}
void MultiplePack(int cost,int weight,int amount)
{
    int k;
    if(cost*amount>=V)
    {
        CompletePack(cost,weight);
        return;
    }
    k=1;
    while(k<amount)
    {
        ZeroOnePack(k*cost,k*weight);
        amount=amount-k;
        k=k*2;
    }
    ZeroOnePack(amount*cost,amount*weight);
}
int main()
{
    int n,i;
    scanf("%d %d",&n,&V);
                                                   // 两种不同的初始化方式,根据情况自行选择 
    //memset(f,0,sizeof(f[0])*(V+1));              // 只希望价格尽量大 
    //memset(f,-M,sizeof(f[0])*(V+1));f[0]=0;      // 要求恰好装满背包 
    for(i=0;i<n;i++) scanf("%d %d %d",m+i,c+i,w+i);
    for(i=0;i<n;i++) MultiplePack(c[i],w[i],m[i]);
    printf("%d\n",f[V]);
    system("PAUSE");
    return 0;
}


多重背包java模板
 

import java.util.Scanner;
public class 多重背包模板 {
    static int c[]=new int[100000]; //一个物品所占空间大小
    static int w[]=new int[100000];//一个物品所拥有的价值
    static int m[]=new int[100000];//一个物品的数目
    static int dp[]=new int[100000];//当放入第i个物品时,背包里物品的最大价值
    static int n,W;
   
    public static void main(String[] args) {
        // TODO Auto-generated method stub
         Scanner sc=new Scanner(System.in);
         n=sc.nextInt();  //总共有n个物品
         W=sc.nextInt();  //背包最大容量
         for(int i=1;i<=n;i++)
         {
             c[i]=sc.nextInt();
             w[i]=sc.nextInt();
             m[i]=sc.nextInt();
         }
         for(int i=1;i<=n;i++)
         {
             MultiplePack(c[i],w[i],m[i]);
         }
         System.out.println(dp[W]);
    }
    private static void ZeroOnePack(int cost,int weight)
        {
            for(int i=W;i>=cost;i--)
            {
                dp[i]=Math.max(dp[i], dp[i-cost]+weight);
            }
        }
    private static void CompletePack(int cost,int weight)
    {
           for(int i=cost;i<=W;i++)
           {
               dp[i]=Math.max(dp[i], dp[i-cost]+weight);
           }
    }
    private static void MultiplePack(int cost, int weight, int amount) {
        // TODO Auto-generated method stub
        int k;
        if(cost*amount>=W)
        {
            CompletePack(cost,weight);
            return;
        }
        k=1;
        while(k<amount)
        {
            ZeroOnePack(k*cost,k*weight);
            amount-=k;
            k=k*2;
        }
        ZeroOnePack(amount*cost,amount*weight);
    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值