题意:给你n个礼物重量,给你一个M力量,看你一次性搬动不超过M的礼物重量。
思路:看似背包,但M太大。所以要用DFS,但n也有45,所以考虑双向DFS先搜前半部分满足情况的所有重量,然后去重,再往后半部分搜索,并二分找答案。
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<queue> #define ll long long using namespace std; const int maxn=(1<<24)+10; ll n,m; ll a[maxn],b[maxn]; ll k; ll ans; bool cmp(ll a,ll b) { return a>b; } ll find(ll sum) { // printf("m-sum: %lld ",m-sum); int y=k; if(b[y]>m-sum) y=upper_bound(b+1,b+1+k,m-sum)-b-1; // printf("y: %d ",y); ans=max(ans,b[y]+sum); } int dfs(int x,ll sum) { if(x==(n/2+2)+1) { b[++k]=sum; return 1; } dfs(x+1,sum); if(sum+a[x]<=m) dfs(x+1,sum+a[x]); } int dfs2(int x,ll sum) { if(x==n+1) { find(sum); return 1; } dfs2(x+1,sum); if(sum+a[x]<=m) dfs2(x+1,sum+a[x]); } int main() { scanf("%lld%lld",&m,&n); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); } sort(a+1,a+n+1,cmp); dfs(1,0); sort(b+1,b+k+1); k=unique(b+1,b+k+1)-(b+1); dfs2(n/2+3,0); printf("%lld ",ans); }