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;
}

posted @ 2020-11-28 21:13  cjlworld  阅读(58)  评论(0编辑  收藏  举报