• hdu 2191 (多重背包+二进制优化)


    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
     
    Author
    lcy

    比较直白的(数据较小):

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <memory.h>
     4 using namespace std;
     5 
     6 int c[105], w[105], n[105];
     7 int bag[105];
     8 int N, V;
     9 
    10 void _mul_bag()     //多重背包:直接转换成01背包(数据比较小)
    11 {
    12     int i, j, k;
    13     memset(bag, 0, sizeof(bag));
    14     for(i = 0; i < N; i++)
    15     {
    16         for(k = 1; k <= n[i]; k++)
    17         {
    18             for(j = V; j >= c[i]; j--)
    19             {
    20                 bag[j] = max(bag[j], bag[j-c[i]] + w[i]);
    21             }
    22         }
    23     }
    24 }
    25 
    26 int main()
    27 {
    28     int i, t;
    29     scanf("%d", &t);
    30     while(t--)
    31     {
    32         scanf("%d %d", &V, &N);
    33         for(i = 0; i < N; i++)
    34             scanf("%d %d %d", &c[i], &w[i], &n[i]);
    35         _mul_bag();
    36         printf("%d
    ", bag[V]);
    37     }
    38 
    39     return 0;
    40 }
    View Code

     二进制优化:

     1 在这之前,我空间好像转过一个背包九讲,现在我就只对  
     2     01背包和多重背包有点印象了  
     3   
     4     先说下 01 背包,有n 种不同的物品,每个物品有两个属性  
     5     size 体积,value 价值,现在给一个容量为 w 的背包,问  
     6     最多可带走多少价值的物品。  
     7   
     8     int f[w+1];   //f[x] 表示背包容量为x 时的最大价值  
     9     for (int i=0; i<n; i++)  
    10         for (int j=w; j>=size[i]; j++)  
    11             f[j] = max(f[j], f[j-size[i]]+value[i]);  
    12   
    13     如果物品不计件数,就是每个物品不只一件的话,稍微改下即可  
    14     for (int i=0; i<n; i++)  
    15         for (int j=size[i]; j<=w; j++)  
    16             f[j] = max(f[j], f[j-size[i]]+value[i]);  
    17   
    18     f[w] 即为所求  
    19   
    20     初始化分两种情况  
    21     1、如果背包要求正好装满则初始化 f[0] = 0, f[1~w] = -INF;  
    22     2、如果不需要正好装满 f[0~v] = 0;  
    23   
    24     多重背包问题要求很简单,就是每件物品给出确定的件数,求  
    25     可得到的最大价值  
    26   
    27     多重背包转换成 01 背包问题就是多了个初始化,把它的件数C 用  
    28     分解成若干个件数的集合,这里面数字可以组合成任意小于等于C  
    29     的件数,而且不会重复,之所以叫二进制分解,是因为这样分解可  
    30     以用数字的二进制形式来解释  
    31     比如:7的二进制 7 = 111 它可以分解成 001 010 100 这三个数可以  
    32     组合成任意小于等于7 的数,而且每种组合都会得到不同的数  
    33 = 1111 可分解成 0001  0010  0100  1000 四个数字  
    34     如果13 = 1101 则分解为 0001 0010 0100 0110 前三个数字可以组合成  
    35     7以内任意一个数,加上 0110 = 6 可以组合成任意一个大于6 小于13  
    36     的数,虽然有重复但总是能把 13 以内所有的数都考虑到了,基于这种  
    37     思想去把多件物品转换为,多种一件物品,就可用01 背包求解了。  
    38   
    39   
    40     看代码:  
    41     int n;  //输入有多少种物品  
    42     int c;  //每种物品有多少件  
    43     int v;  //每种物品的价值  
    44     int s;  //每种物品的尺寸  
    45     int count = 0; //分解后可得到多少种物品  
    46     int value[MAX]; //用来保存分解后的物品价值  
    47     int size[MAX];  //用来保存分解后物品体积  
    48   
    49     scanf("%d", &n);    //先输入有多少种物品,接下来对每种物品进行分解  
    50   
    51     while (n--) {   //接下来输入n中这个物品  
    52         scanf("%d%d%d", &c, &s, &v);  //输入每种物品的数目和价值  
    53         for (int k=1; k<=c; k<<=1) { //<<右移 相当于乘二  
    54             value[count] = k*v;  
    55             size[count++] = k*s;  
    56             c -= k;  
    57         }  
    58         if (c > 0) {  
    59             value[count] = c*v;  
    60             size[count++] = c*s;  
    61         }  
    62     }  
    63   
    64     现在用count 代替 n 就和01 背包问题完全一样了
    View Code

    背包九讲里面,他的实现方法和这个是不一样的,利用01背包和完全背包来配合实现的,下面是实现:

     1 /* 
     2 HDOJ 2191 
     3 多重背包用二进制转化的思想,进行优化 
     4 */  
     5   
     6 #include <iostream>  
     7 using namespace std;  
     8   
     9 int weight[110],Value[110],num[110];  
    10 int f[1100];  
    11 int limit;  
    12   
    13 inline void ZeroOnePack(int w,int v)  
    14 {  
    15     int j;  
    16     for(j=limit;j>=w;j--)  
    17     {  
    18         if(f[j-w]+v > f[j])  
    19             f[j]=f[j-w]+v;  
    20     }  
    21 }  
    22   
    23 inline void CompletePack(int w,int v)  
    24 {  
    25     int j;  
    26     for(j=w;j<=limit;j++)  
    27     {  
    28         if(f[j-w]+v > f[j])  
    29             f[j]=f[j-w]+v;  
    30     }  
    31 }  
    32   
    33 inline void MultiplePack(int w,int v,int amount)  
    34 {  
    35     if(amount * w >= limit)  
    36     {  
    37         CompletePack(w,v);  
    38         return ;  
    39     }  
    40     for(int k=1;k<amount;k<<=1)  
    41     {  
    42         ZeroOnePack(k*w,k*v);  
    43         amount -= k;  
    44     }  
    45     ZeroOnePack(amount*w,amount*v);  
    46 }  
    47   
    48 int main()  
    49 {  
    50     int T,n;  
    51     cin>>T;  
    52     while(T--)  
    53     {  
    54         cin>>limit>>n;  
    55           
    56         for(int i=0;i<n;i++)  
    57             cin>>weight[i]>>Value[i]>>num[i];  
    58           
    59         memset(f,0,sizeof(f));  
    60           
    61         for(i=0;i<n;i++)  
    62             MultiplePack(weight[i],Value[i],num[i]);  
    63           
    64         cout<<f[limit]<<endl;  
    65     }  
    66     return 0;  
    67 }
    View Code
     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 using namespace std;
     5 int t,v,n;
     6 int c[109],w[109],num[109],F[109];
     7 
     8 void zeroonebag(int cost,int weight){
     9      for(int i=v;i >= cost;i--) F[i]=max(F[i],F[i-cost]+weight);
    10 }
    11 
    12 void completebag(int cost,int weight){
    13      for(int i=cost;i <= v;i++) F[i]=max(F[i],F[i-cost]+weight);
    14 }
    15 
    16 void multiplybag(int cost,int weight,int num){
    17      if(cost*num >= v) completebag(cost,weight);
    18      else{
    19         int k=1,m=num;
    20         while(k < m){
    21             zeroonebag(k*cost,k*weight);
    22             m-=k;
    23             k*=2;
    24         }
    25         zeroonebag(m*cost,m*weight);
    26      }
    27 }
    28 
    29 int main(void){
    30     scanf("%d",&t);
    31     while(t--){
    32         scanf("%d%d",&v,&n);
    33         for(int i=0;i < n;i++) scanf("%d%d%d",&c[i],&w[i],&num[i]);
    34         memset(F,0,sizeof(F));
    35         for(int i=0;i < n;i++) multiplybag(c[i],w[i],num[i]);
    36         printf("%d
    ",F[v]);
    37     }
    38     return 0;
    39 }
    View Code

    单调队列:http://www.cppblog.com/flyinghearts/archive/2010/09/01/125555.aspx 

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 #include <math.h>
     5 #include <algorithm>
     6 #include <iostream>
     7 using namespace std;
     8 int dp[102];
     9 int p[102],h[102],c[102];
    10 int n,m;
    11 void comback(int v,int w)//经费,重量。完全背包;
    12 {
    13     for(int i=v; i<=n; i++)
    14         if(dp[i]<dp[i-v]+w)
    15             dp[i]=dp[i-v]+w;
    16 }
    17 void oneback(int v,int w)//经费,重量;01背包;
    18 {
    19     for(int i=n; i>=v; i--)
    20         if(dp[i]<dp[i-v]+w)
    21             dp[i]=dp[i-v]+w;
    22 }
    23 int main()
    24 {
    25     int ncase,i,j,k;
    26     scanf("%d",&ncase);
    27     while(ncase--)
    28     {
    29         memset(dp,0,sizeof(dp));
    30         scanf("%d%d",&n,&m);//经费,种类;
    31         for(i=1; i<=m; i++)
    32         {
    33             scanf("%d%d%d",&p[i],&h[i],&c[i]);//价值,重量,数量;
    34             if(p[i]*c[i]>=n) comback(p[i],h[i]);
    35             else
    36             {
    37                 for(j=1; j<c[i]; j=j*2)
    38                 {
    39                     oneback(j*p[i],j*h[i]);
    40                     c[i]=c[i]-j;
    41                 }
    42                 oneback(p[i]*c[i],h[i]*c[i]);
    43             }
    44         }
    45         printf("%d
    ",dp[n]);
    46     }
    47     return 0;
    48 }
  • 相关阅读:
    在指定文件夹目录下打开jupyter notebook
    防止sql注入
    惰性函数——适合外层函数只需要执行一次
    Text类型
    怎样理解阻塞非阻塞与同步异步的区别?
    Element类型
    避免使用eval()
    javascript 连等赋值问题
    类数组转化为数组
    DOM10-1节点层次
  • 原文地址:https://www.cnblogs.com/wangmengmeng/p/4835694.html
Copyright © 2020-2023  润新知