多重背包

链接:https://ac.nowcoder.com/acm/problem/235950 来源:牛客网

做法:适用于物品数量不是无限但又不止一个的背包问题,一开始想到的是将n个相同重量的物品当作n个不同的物品,但完全背包的复杂度已经汗流浃背,所以我们需要把这个重复的n进行优化,我们尽量去把2的幂作为一组进行打包,剩下的再作为一组打包,这样我们就能用我们构造的数去凑出任何一个1到n之间的数(拆位),那么之后就是经典01背包,这里用嵌套pair去存储(懒。

//本题代码
#include<bits/stdc++.h>
#define endl "\n"
#define ll long long
//dont forget to check long long
//别写重变量名
//记得判越界
//别死磕
//处理字符串删掉关流
std::vector<std::pair<int,std::pair<int,int>>> a;
int f[510000];
void op(int x,int w,int v)
{
    int u=0;
    int xx=x;
    while(xx)
    {
        if((1<<u)<=xx)
        {
            //std::cout<<(1<<u)<<" "<<xx<<endl;
            a.push_back({(1<<u),{w,v}});
            xx-=(1<<u);
            u++;
        } 
        else break;
    }
    //std::cout<<xx<<endl;
    a.push_back({xx,{w,v}});
}
void slove()
{
    int n,m;
    std::cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        int x,w,v;
        std::cin>>x>>w>>v;
        op(x,w,v);
    }
    f[0]=0;
    for(int i=0;i<(int)a.size();i++)
    {
        for(int j=m;j>=a[i].first*a[i].second.first;j--)
        {
            if(j>=a[i].first*a[i].second.first)
            f[j]=std::max(f[j],f[j-a[i].first*a[i].second.first]+a[i].first*a[i].second.second);
        }
    }
    std::cout<<f[m]<<endl;
}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int T=1; 
    //std::cin>>T;
    while(T--)    {
        slove();
    }

    return 0;
}