算法标签:双向dfs
题目链接:送礼物
题目大意:
有m个礼物,给定每个礼物的重量,在重量不超过w的情况下,求最大的重量
思路:因为此题w的范围为[1,2^31-1],故不能用背包去解,因为1<=m<=46,可以想到用dfs,但一般的dfs肯定会超,所以想到可以用双向dfs,先搜前一半,打个表,把所有的情况都列出来,再搜后一半,当搜到第m个时,再利用二分去表中查找第一个<=(w-当前后一半的重量),记录下最优解。
代码如下:
#include<bits/stdc++.h> using namespace std; #define sf(x) scanf("%lld",&x) #define sff(x,y) scanf("%lld%lld",&x,&y) #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define pii pair<int,int> #define f first #define s second #define int long long const int N=25; int a[100],q[1<<N],w,m,cnt=1,res; void dfs1(int u ,int d,int sum) { if(u==d) { q[cnt++]=sum; return ; } //选 if(sum+a[u]<=w) dfs1(u+1,d,sum+a[u]); //不选 dfs1(u+1,d,sum); } void dfs2(int u,int sum) { if(u==m){ //二分查找前一半 int l=0,r=cnt,nu=w-sum; while(l+1<r) { int mid =l+r>>1; if(q[mid]<=nu) l=mid; else r=mid; } res=max(res,q[l]+sum); return ; } //选 if(sum+a[u]<=w) dfs2(u+1,sum+a[u]); //不选 dfs2(u+1,sum); } signed main() { cin>>w>>m; for(int i=0;i<m;i++) cin>>a[i]; sort(a,a+m); reverse(a,a+m);//剪枝(从大到小枚举,优化搜索顺序) int k=m/2; dfs1(0,k,0);//先搜前一半打个表 sort(q+1,q+1+cnt); cnt=unique(q+1,q+1+cnt)-q;//去重 dfs2(k,0);//再搜后一半 cout<<res; }