[编程题] 牛牛的背包问题
时间限制: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
输出例子1:
8
例子说明1:
三种零食总体积小于10,于是每种零食有放入和不放入两种情况,一共有2*2*2 = 8种情况。
对于后15个也同样这样做。 记为u2
这样结果等于u1中的每个元素与u2中的每个元素简单的双重循环相加,只要结果不大于背包容量即可,每符合一个结果总数便加一。
可以先给u1和u2排序,然后使用二分查找加速这个过程,要不然还是超时,跟直接搜索30个没区别。
//网易2019实习生招聘编程题集合 [编程题] 牛牛的背包问题
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
ll n,w;
vector<ll> v1,v2;
vector<ll> u1,u2;
void dfs1(ll pos,ll cap) {
if(pos==v1.size()) {
u1.push_back(w-cap);
return;
}
dfs1(pos+1,cap);
if(cap>=v1[pos]) {
dfs1(pos+1,cap-v1[pos]);
}
}
void dfs2(ll pos,ll cap) {
if(pos==v2.size()) {
u2.push_back(w-cap);
return;
}
dfs2(pos+1,cap);
if(cap>=v2[pos]) {
dfs2(pos+1,cap-v2[pos]);
}
}
int getindex(ll rem) {
int l=0,r=u2.size()-1;
if(u2[r]<=rem) return r;
if(u2[l]>rem) return -1;
while(1) {
int mid=(l+r)/2;
if(rem<u2[mid]) {
r=mid;
}else if(rem>=u2[mid]&&rem<u2[mid+1]) {
return mid;
}else {
l=mid;
}
}
}
int main() {
cin>>n>>w;
int an=n/2,bn=n-an;
for(int i=0;i<an;i++) {
ll c; cin>>c;
if(c<=w) v1.push_back(c);
}
for(int i=0;i<bn;i++) {
ll c; cin>>c;
if(c<=w) v2.push_back(c);
}
dfs1(0,w);
dfs2(0,w);
sort(u1.begin(),u1.end());
sort(u2.begin(),u2.end());
//for(int i=0;i<u1.size();i++) cout<<"u1 "<<u1[i]<<endl;
//for(int i=0;i<u2.size();i++) cout<<"u2 "<<u2[i]<<endl;
ll res=0;
for(int i=0;i<u1.size();i++) {
ll rem=w-u1[i];
int index=getindex(rem);
res+=(index+1);
}
cout<<res<<endl;
}