题目链接:https://www.acwing.com/problem/content/173/
要求从n件物品中选出若干件,重量之和不超过w并且最接近w,由于有45件最多,所以O(2^n)时间复杂度过高,可以考虑减半先搜索出结果,用另一半在前一半中二分寻找,
最终拼成结果,时间复杂度约为O(2^n/2*n)。中间有一个优化是将所有物品的重量进行降序排序,这样做可以使得子集和更快的趋近w和,决策的数量将会变少。
代码:
#include<iostream> #include<cstdio> #include<vector> #include<algorithm> using namespace std; #define maxn 100 typedef long long ll; unsigned int n,w,g[maxn]; vector<unsigned int > v; unsigned int ans; int m ; void dfs1(int now,unsigned int tot){//搜索前一半 if(!now){ v.push_back(tot); return ; } dfs1(now-1,tot);//不选第i件, if(g[now]+tot <= w)dfs1(now-1,g[now]+tot); } void dfs2(int now,unsigned int tot){ if(now==n+1){ unsigned int y=*--upper_bound(v.begin(),v.begin()+m,w-tot);//查找最后一个小于等于w-tot的值 ans=max(ans,tot+y); return; } dfs2(now+1,tot); if(g[now]+tot <= w)dfs2(now+1,g[now]+tot); } bool cmp(unsigned int &a,unsigned int &b){return a>b;} int main(){ cin>>w>>n; for(int i=1;i<=n;i++)cin>>g[i]; sort(g+1,g+n+1,cmp);//优化搜索顺序 int k=n/2+2; dfs1(k,0);//先处理出前一半 sort(v.begin(),v.end()); m=unique(v.begin(),v.end())-v.begin(); dfs2(k+1,0); cout<<ans<<endl; }