• 超大背包问题 二分枚举 pair数组应用 位运算表示集合


    超大背包问题 二分枚举 pair数组应用 位运算表示集合

    关键词

    二分枚举 pair数组应用 位运算表示集合 二分搜索

    笺释

    我觉得这道题真是很好很好,设计到的三个知识点我只对位运算熟悉一点,其他两个的话于我而言都感觉又多明白了一点,算法科学真美啊。
    因为开不出来这么大的背包,但是n比较小,于是考虑用枚举,但是枚举的话2n会超时(顺便一提2n应该是并不会超内存的,最大用ll开到过n=50的情况)。所以二分枚举就好了。

    至于为什么能够二分枚举

    我认为能二分枚举的题目都有这样的特征分成两半后,带着前一半的数据取处理后一半的数据能够得到最终数据。,我想说的并不是这种可以分成两半的结构还是可以归并的结构,我觉得更有意思的是这很像是二分答案不是吗,带着已知的一部分答案去查找另一部分。

    然后一个很厉害的地方就是对pair组的应用

    在做这道题之前一直以为pair数组不就是map吗,他能做的map都能做。现在完全不这样想了,也可能是我太困了脑筋转不动了,但是我觉得这道题把数据结构换成map是没办法做的。
    先是去掉了pair数组中重量大但是价值低的物品,一定是不拿的。
    这时候数组中任意一个都满足,重量大,价值一定也大。
    我们要找到第二部分里能取的(w小于W-w1)里v最大的只需要找到i最大的,他的v一定最大。

    还要注意lowerbond的用法

    找到的是最小的大于等于W-w1的嘛,那前一个就是我们能取的最大的了,因为pair组是按照W排序的。
    但是注意这道题make_pair()第二个参数只能是INF,至于为什么,我目前还不太理解。

    完整代码(未严格测试)

    #include<bits/stdc++.h>
    #define MAXN 45
    const long long INF =0x3f3f3f3f;
    using namespace std;
    int n;
    long long w[MAXN],v[MAXN];
    long long W;
    pair<long long,long long>ps[1<<MAXN/2];
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&w[i]);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&v[i]);
        }
        scanf("%lld",&W);
        int n2=n/2;
        for(int i=0;i<=(1<<n2)-1;i++)
        {
            long long vv=0,ww=0;
            for(int j=1;j<=n2;j++)
            {
                if(i>>(j-1)&1)
                {
                 //   printf("ss
    ");
                    vv+=v[j];
                    ww+=w[j];
                }
            }
            //按照w排序才行
            ps[i]=make_pair(ww,vv);
        }
        //
        sort(ps,ps+(1<<n2));
        int m=1;
        //从0到m-1按照pair增序
        for(int i=1;i<=(1<<n2)-1;i++)
        {
            if(ps[m-1].second<ps[i].second)
            {
                ps[m++]=ps[i];
            }
        }
        int sn2=n-n2;
        long long ans=0;
        for(int i=0;i<=(1<<sn2)-1;i++)
        {
            long long vv=0,ww=0;
            for(int j=1;j<=sn2;j++)
            {
                if(i>>(j-1)&1)
                {
                    vv+=v[j+n2];
                    ww+=w[j+n2];
                }
            }
            //按照w排序才行
            if(ww<=W)
            {
                long long tv=(lower_bound(ps,ps+m,make_pair(W-ww,INF))-1)->second;
                ans=max(ans,tv+vv);
            }
        }
        printf("%lld
    ",ans);
    }
    //4 2 1 3 2 3 2 4 2 5
    
  • 相关阅读:
    CSS命名规范
    dev 从表处理
    core直接获取报异常数据
    SQL根据指定节点ID获取所有父级节点和子级节点(转载)
    bootstrap的tree使用
    ef报错(因为相同类型的其他实体已具有相同的主键值)
    yii初体验(2)创建方法
    yii初体验(1)composer安装+环境检测
    layui数据表格中图片无法自适应问题
    tp5查询数据库排除某字段
  • 原文地址:https://www.cnblogs.com/SoniciSika/p/9038953.html
Copyright © 2020-2023  润新知