• 混合背包问题


    题面连接

    题面

    (N) 种物品和一个容量是 (V) 的背包。

    物品一共有三类:

    • 第一类物品只能用(1)次(01背包);
    • 第二类物品可以用无限次(完全背包);
    • 第三类物品最多只能用 (si) 次(多重背包);

    每种体积是 (vi),价值是 (wi)

    求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
    输出最大价值。

    输入格式

    第一行两个整数,N,VN,V,用空格隔开,分别表示物品种数和背包容积。

    接下来有 N 行,每行三个整数 (vi,wi,si),用空格隔开,分别表示第 i 种物品的体积、价值和数量。

    • (si=−1)表示第 (i) 种物品只能用1次;
    • (si=0) 表示第(i) 种物品可以用无限次;
    • (si>0) 表示第 (i) 种物品可以使用 (si) 次;

    输出格式

    输出一个整数,表示最大价值。

    数据范围

    (0<N,V≤1000)
    (0<vi,wi≤1000)
    (−1≤si≤1000)

    输入样例

    4 5
    1 2 -1
    2 4 1
    3 4 0
    4 5 2
    

    输出样例:

    8
    

    思路

    把多重背包,完全背包都转化成01背包

    但是需要进行二进制优化

    代码

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<utility>
    #include<vector>
    using  namespace std;
    typedef pair<int,int > PII;
    #define x first
    #define y second
    const int N=200000;
    vector<PII> G;
    int f[N];
    int n,m;
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            int v,w,s;
            scanf("%d%d%d",&v,&w,&s);
            if(s==0)//完全背包的最大物品数就是m/v
            {
                s=m/v; 
                for(int k=1;k<=s;)
                {
                    G.push_back({v*s,w*s});
                    s-=k;
                    k*=2;
                }
                if(s)
                    G.push_back({v*s,w*s});
            }
            else if(s<0)//01背包
            {
                G.push_back({v,w});
            }
            else {//多重背包
                for(int k=1;k<=s;)
                {
                    G.push_back({v*s,w*s});
                    s-=k;
                    k*=2;
                }
                if(s)
                    G.push_back({v*s,w*s});
            }
        }
        for(int i=0;i<G.size();i++)
            for(int j=m;j>=G[i].first;j--)
            {
                f[j]=max(f[j],f[j-G[i].first]+G[i].second);//01背包的套路
            }
        cout<<f[m]<<endl;
        return 0;
    }
    
  • 相关阅读:
    第一章--linux基础
    深入浅出OOP(一): 多态和继承(早期绑定/编译时多态)
    LeetCode Letter Combinations of a Phone Number
    ios 仿android gallery控件
    android何如获取SIM卡提供国家代码(ISO)
    android 获取 imei号码
    overridePendingTransition的简介
    转 Android Activity之间动画完整版详解
    【android开发】使用PopupWindow实现页面点击顶部弹出下拉菜单
    Android 带你从源码的角度解析Scroller的滚动实现原理
  • 原文地址:https://www.cnblogs.com/bangdexuanyuan/p/13949695.html
Copyright © 2020-2023  润新知