网易2019实习生招聘笔试-牛牛的背包问题

时间限制:1秒

空间限制:32768K

牛牛准备参加学校组织的春游, 出发前牛牛准备往背包里装入一些零食, 牛牛的背包容量为w。
牛牛家里一共有n袋零食, 第i袋零食体积为v[i]。
牛牛想知道在总体积不超过背包容量的情况下,他一共有多少种零食放法(总体积为0也算一种放法)。

输入描述:
输入包括两行
第一行为两个正整数n和w(1 <= n <= 30, 1 <= w <= 2 * 10^9),表示零食的数量和背包的容量。
第二行n个正整数v[i](0 <= v[i] <= 10^9),表示每袋零食的体积。


输出描述:
输出一个正整数, 表示牛牛一共有多少种零食放法。

输入例子1:
3 10
1 2 4

如题,最容易想到的方法是位运算或者dfs枚举,分别取得了60%和80%的“优秀”成绩,先贴代码

#include <iostream>
#include <cstdio>
#include <cstring>
#define LL long long
using namespace std;
LL n;
LL v,k;
LL a[33];
LL cnt=0;
int flag=1;
int main(){
    cin>>n>>v;
    for(LL i=0;i<n;i++){
        cin>>a[i];
    }
    LL s=1<<n,now_v=0;
    for(LL i=0;i<s;i++){
        now_v=0;
        for(LL j=0;j<n;j++){
            k=(1<<j);
            if((i&k)==k){
                now_v+=a[j];
                //cout<<i<<" "<<k<<" "<<now_v<<endl;
                if(now_v>v){
                    break;
                }
            }
        }
        if(now_v<=v){
            //cout<<now_v<<endl;
            cnt+=1;
            //cout<<now_v<<" "<<i<<endl;
        }
    }
    cout<<cnt<<endl;
    return 0;
}
#include <iostream>
#include <cstdio>
#include <cstring>
#define LL long long
using namespace std;
LL n;
LL v,k;
LL a[33];
LL cnt=0;
void dfs(int k,LL s){

    if(k==n){
        cnt+=1;
        return ;
    }
    if(s+a[k]<=v){
        dfs(k+1,s+a[k]);
    }
    dfs(k+1,s);
}
int main(){
    scanf("%lld%lld",&n,&v);
    for(LL i=0;i<n;i++){
        scanf("%lld",&a[i]);
    }
    dfs(0,0);
    printf("%lld\n",cnt);
    return 0;
}

显然2^30的复杂度是不被允许的,暴力枚举不可取,通过大神的点拨后想到将30分成两份,把我们能接受的前15个物品先进行第一次枚举搜索,然后再对剩下的物品进行第二次枚举搜索。把第二次枚举搜索出来的结果(至多2^15=32768个答案)存入数组并排序,枚举第一次搜出来的结果,计算出还剩下多少背包体积还能装,在第二次的结果中进行二分搜索,并把两次搜索的结果进行相乘(乘法原理)。再把所有的结果进行相加(加法原理),就是答案了。

#include <iostream>
#include <map>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
long long a[50];
int main()
{
    int n;
    long long m;
    cin>>n>>m;
    for(int i=0;i<n;++i)
        cin>>a[i];
    if(n<20)
    {
        int ans=0;
        for(int i=0;i<1<<n;++i)
        {
            long long weight=0;
            for(int j=0;j<n;++j)
                if((i&(1<<j))!=0)
                    weight+=a[j];
            if(weight<=m)
                ans++;
        }
        cout<<ans<<endl;
        return 0;
    }
    long long b[20];
    for(int i=0;i<15;++i)
        b[i]=a[i];
    long long c[20];
    for(int i=0;i<n-15;++i)
        c[i]=a[i+15];
    map<long long,int>mp;
    for(int i=0;i<(1<<15);++i)
    {
        long long weight=0;
        for(int j=0;j<15;++j)
            if((i&(1<<j))!=0)
                weight+=b[j];
        if(weight>m)
            continue;
        if(mp.find(weight)!=mp.end())
            mp[weight]++;
        else mp[weight]=1;
    }
    //cout<<mp.size()<<endl;
    int last=n-15;
    map<long long,int>another;
    for(int i=0;i<(1<<last);++i)
    {
        long long weight=0;
        for(int j=0;j<last;++j)
            if((i&(1<<j))!=0)
                weight+=c[j];
        if(weight>m)
            continue;
        if(another.find(weight)!=another.end())
            another[weight]++;
        else another[weight]=1;
    }
    vector<pair<long long,int> >vec;
    for(map<long long,int>::iterator it=another.begin();it!=another.end();++it)
        vec.push_back(make_pair(it->first,it->second));
    for(int i=1;i<vec.size();++i)
       vec[i].second+=vec[i-1].second;
    long long ans=0;
    for(map<long long,int>::iterator it=mp.begin();it!=mp.end();++it)
    {
        long long p=m-(it->first);
        int q=lower_bound(vec.begin(),vec.end(),make_pair(p,0))-vec.begin();
        ans+=vec[q-1].second*(it->second);
    }
    cout<<ans<<endl;
}


猜你喜欢

转载自blog.csdn.net/q295657451/article/details/79731143