混合背包

Description

背包体积为C,给出N个物品,每个物品占用体积为Vi,价值为Wi,每个物品要么至多取1件,要么至多取Mi件(Mi > 1),要么数量无限,在所装物品总体积不超过C的前提下所装物品的价值的和的最大值是多少?

Input

多测试用例。

第一行两个数NCC ≤ 200000,N ≤ 200),下面N行每行三个数ViWiMi分别表示每个物品的体积、价值与数量,Mi=1表示至多取一件,Mi>1表示至多取Mi件,Mi=-1表示数量无限。

Output

输出一行结果:所装物品价值的最大值。

Sample Input

2 10
3 7 2
2 4 -1

Sample Output

22

AC代码:
#include <iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;

const int maxn = 200000+10;
const int maxc = 1e9+7;

LL f[maxn];
int v[210],w[210],m[210];
int n,V;

void ZeroOnePack(int cost,int weight)//0-1背包
{
    for(int j=V;j>=cost;j--)
    f[j]=max(f[j],f[j-cost]+weight);
}
void CompletePack(int cost ,int weight)//完全背包
{
    for(int j=cost;j<=V;j++)
    f[j]=max(f[j],f[j-cost]+weight);
}
void MultiPack(int cost,int weight,int amount)//多重背包
{
    if(cost*amount>=V)
    {
        CompletePack(cost,weight);
        return;
    }
    int k=1;
    while(k<amount)
    {
        ZeroOnePack(k*cost,k*weight);
        amount-=k;
        k*=2;
    }
    ZeroOnePack(amount*cost,amount*weight);
}

int main()
{
    while(scanf("%d%d",&n,&V)!=EOF)
    {
    memset(f,0,sizeof(f));
    for(int i=1;i<=n;i++)
    scanf("%d %d %d",&v[i],&w[i],&m[i]);
    for(int i=1;i<=n;i++)
    {
        if(m[i]==1)//0-1背包
        {
            ZeroOnePack(v[i],w[i]);
        }
        else if(m[i]==-1)//完全背包
        {
            CompletePack(v[i],w[i]);
        }
        else //多重背包
        {
            MultiPack(v[i],w[i],m[i]);
        }
    }
    cout<<f[V]<<endl;
    }
    return 0;
}
View Code

 

posted @ 2018-05-15 21:34  shuai_hui  阅读(151)  评论(0编辑  收藏  举报