时间限制: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;
}