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

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

关键词

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

笺释

我觉得这道题真是很好很好,设计到的三个知识点我只对位运算熟悉一点,其他两个的话于我而言都感觉又多明白了一点,算法科学真美啊。
因为开不出来这么大的背包,但是n比较小,于是考虑用枚举,但是枚举的话2^n会超时(顺便一提2^n应该是并不会超内存的,最大用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\n");
                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\n",ans);
}
//4 2 1 3 2 3 2 4 2 5

猜你喜欢

转载自www.cnblogs.com/SoniciSika/p/9038953.html
今日推荐