• luogu||P1776||宝物筛选||多重背包||dp||二进制优化


    题目描述

    终于,破解了千年的难题。小FF找到了王室的宝物室,里面堆满了无数价值连城的宝物……这下小FF可发财了,嘎嘎。但是这里的宝物实在是太多了,小FF的采集车似乎装不下那么多宝物。看来小FF只能含泪舍弃其中的一部分宝物了……小FF对洞穴里的宝物进行了整理,他发现每样宝物都有一件或者多件。他粗略估算了下每样宝物的价值,之后开始了宝物筛选工作:小FF有一个最大载重为W的采集车,洞穴里总共有n种宝物,每种宝物的价值为v[i],重量为w[i],每种宝物有m[i]件。小FF希望在采集车不超载的前提下,选择一些宝物装进采集车,使得它们的价值和最大。

    思路

    典型的多重背包+二进制优化dp,看过背包九讲以后来水一波题,看到网上很多神犇利用左移右移来进行优化,我只能Orz,我先使用预处理,反正数字利用二进制优化以后不会太大,预处理到2^30,将物品的件数分解,最后利用0/1背包的模板输出答案,代码如下

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<ctime>
    #include<cmath>
    #include<iomanip>
    
    using namespace std;
    const int maxn=666666;
    int n,max_weight;
    int ans=0;
    int f[maxn],weight[maxn],nums[maxn],values[maxn];
    int k2[50],k2s[50];
    void prem()//处理2^k
    {   
        int sum=2;
        k2[1]=1;k2s[1]=1;k2s[0]=0;
        for(int i=2;i<=30;i++)
        {
            k2[i]=k2[i-1]*2;
            k2s[i]=k2s[i-1]+k2[i];
        }
    }
    int prek(int m)//处理系数
    {
        for(int i=1;i<=m;i++)
        {
            if(m==1)
                return 0;
            if(m==2)
                return 1;
            if(m<k2[i])
                return i-1;
        }
    } 
    int sum=0;
    void input()
    {
        cin>>n>>max_weight;
       
        for(int i=1;i<=n;i++)
        {
            int aa,bb,cc;
            cin>>aa>>bb>>cc;
            int temp=prek(cc);
            cout<<temp<<endl;
            for(int j=1;j<=temp-1;j++)
            {
                sum++;
                weight[sum]=aa;
                values[sum]=bb;
                nums[sum]=k2[j];
            }
            cout<<k2s[temp]<<' '<<cc<<endl;
            //if(k2s[temp]!=cc)
            //{
            if(temp==0)
            {
                sum++;
                weight[sum]=aa;values[sum]=bb;
                nums[sum]=cc;
            }
            else
            {
                sum++;
                weight[sum]=aa;values[sum]=bb;
                nums[sum]=cc-k2[temp]+1;
                /*
                sum++;
                weight[sum]=aa;values[sum]=bb;
                nums[sum]=cc-k2[temp]+1;
                */
            }
            
        }
        //cout<<"*********************************"<<endl;
        /*
        for(int i=1;i<=sum;i++)
        {
            cout<<weight[i]<<' '<<values[i]<<' '<<nums[i]<<endl;
        }
        */
    }
    void solve()
    {
        for(int i=1;i<=sum;i++)
            for(int j=max_weight;j>=weight[i];j--)
            {
                f[j]=max(f[j],f[j-weight[i]]+values[i]);
            }
        cout<<f[max_weight];
    }
    int main()
    {
        prem();
        input();
        solve();
        return 0;
    }

  • 相关阅读:
    基础
    树梅派线程
    超声波
    电脑版微信双开多开
    子类能不能重写父类的构造方法
    window8taskost.exe一直占用cpu
    windows下rocketmq安装
    spring循环依赖问题
    线程池的种类
    并行和并发有什么区别?
  • 原文地址:https://www.cnblogs.com/supersumax/p/9418388.html
Copyright © 2020-2023  润新知