AcWing 171. 送礼物
用STL
,vector
,unique
,sort
,upper_bound
也过了。
此题部分代码被卡的原因是
没有排序,导致两部分 sum>m
的剪枝效果不一,要是前半部分的重量较小,枚举 \(2^{23}\) 自然就挂了。
处理方法有两种
random_shuffle()
,打乱顺序,使剪枝均匀分布。sort()
, 我的建议是升序,然后令dfs1()
的深度最大为 20.这样前半部分最多 \(2^{20}\) 个数,后半部分因为数都较大,大部分被剪掉了,剩的不多,复杂度也可以接受。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<ctime>
#include<cmath>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
//折半搜索
const int N=56;
const LL INF=1e16;
LL n,m,w[N],ans;
vector<LL> v;
void dfs1(int step,int limit,LL sum)
{
if(sum>m) return;
if(step==limit+1) {
ans=max(ans,sum);
v.push_back(sum);
return;
}
dfs1(step+1,limit,sum+w[step]);
dfs1(step+1,limit,sum);
}
void dfs2(int step,int limit,LL sum)
{
if(sum>m) return;
if(step==limit+1) {
// sum+v[u] <= m ---> v[u]<=m-sum
ans=max(ans,sum);
int id=(int)(upper_bound(v.begin(),v.end(),m-sum)-v.begin())-1;
if(id>=0&&v[id]+sum<=m) ans=max(ans,v[id]+sum);
return;
}
dfs2(step+1,limit,sum+w[step]);
dfs2(step+1,limit,sum);
}
int main()
{
cin>>m>>n;
for(int i=1;i<=n;i++)
scanf("%lld",&w[i]);
sort(w+1,w+n+1);
int tmp=min(n,20ll);
dfs1(1,tmp,0);
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
dfs2(tmp+1,n,0);
cout<<ans;
return 0;
}