hdu 2191 珍惜现在,感恩生活 多重背包入门题

背包九讲下载CSDN 

背包九讲内容

多重背包:

hdu 2191 珍惜现在,感恩生活 多重背包入门题

使用将多重背包转化为完全背包与01背包求解;

对于w*num>= V这时就是完全背包,完全背包为何只与01背包在循环上不同,因为01背包,每个物品只能取一次,所以要逆序;而完全背包,每个物品的数量无限多个,这就需要建在在之前已经取到了当前要取的基础之上;

同时01背包使用二进制优化处理;即使用二进制表示最优的可取值;

二进制优化的技巧:1,2,4,...,2k−1,n[i]−2k +1(循环之外),且k是满足n[i]−2k +1 > 0的最大整数。例如,如果n[i]为13,就将这种 物品分成系数分别为1,2,4,6的四件物品。这种方法也能 保证对于0..n[i]间的每一个整数(证明可以分0..2k-1和2k..n[i]两段来分别讨论得出);

 

#include<bits/stdc++.h>
using namespace std;
#define MS0(a) memset(a,0,sizeof(a))
#define MS1(a) memset(a,-1,sizeof(a))
#define inf 0x3f3f3f3f
int f[110],V;
void ZeroOnePack(int w,int c)
{
    for(int v = V;v >= w;v--)
        f[v] = max(f[v],f[v-w]+c);
}
void CompletePack(int w,int c)
{
    for(int v = w;v <= V;v++)
        f[v] = max(f[v],f[v-w]+c);
}
void MultiPack(int w,int c,int num)
{
    if(w*num >= V)
        CompletePack(w,c);
    else{
        for(int k = 1;k < num;k <<= 1){
            ZeroOnePack(w*k,k*c);// 二进制优化可取的数目;01背包只是看当前这件物品取与不取;
            num -= k;
        }
        ZeroOnePack(w*num,c*num);
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        int m,w,c,num;
        MS0(f);
        scanf("%d%d",&V,&m);
        rep1(i,1,m){// 在线即可
            scanf("%d%d%d",&w,&c,&num);
            MultiPack(w,c,num);
        }
        printf("%d\n",f[V]);
    }
}
View Code

 

 

posted @ 2016-02-19 10:12  hxer  阅读(197)  评论(0编辑  收藏  举报