整理的算法模板:ACM算法模板总结(分类详细版)
达达帮翰翰给女生送礼物,翰翰一共准备了N个礼物,其中第i个礼物的重量是G[i]。
达达的力气很大,他一次可以搬动重量之和不超过W的任意多个物品。
达达希望一次搬掉尽量重的一些物品,请你告诉达达在他的力气范围内一次性能搬动的最大重量是多少。
输入格式
第一行两个整数,分别代表W和N。
以后N行,每行一个正整数表示G[i]。
输出格式
仅一个整数,表示达达在他的力气范围内一次性能搬动的最大重量。
数据范围
1≤N≤461≤N≤46,
1≤W,G[i]≤231−11≤W,G[i]≤231−1
输入样例:
20 5
7
5
4
18
1
输出样例:
19
这道题有点背包模型的意思啊,但是背包的时间复杂度是 n * w ;放这道题铁定超了;
然后考虑dfs暴搜,最坏一共2^46次方种方案,铁定爆栈;
于是就要对dfs进行优化了;可以把前2^25次方的情况进行打表,然后暴搜后面的2^21次方的情况,对于每一种情况,二分查表找到最大的符合条件的值;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=50;
ll w[N],s[1<<25],ans,W,n;
int k,cnt=1,len;
void dfs_1(int u,ll sum)//打表
{
if(u==k)
{
s[cnt++]=sum;
return ;
}
dfs_1(u+1,sum);
if(sum+w[u]<=W) dfs_1(u+1,sum+w[u]);
}
void dfs_2(int u,ll sum)
{
if(u==n)
{
ll res=W-sum;
int pos=lower_bound(s,s+len,res,greater<ll>())-s;//二分查表找到符合当前情况的最大值;
if(s[pos]<=res) ans=max(ans,s[pos]+sum);
return ;
}
dfs_2(u+1,sum);
if(w[u]+sum<=W) dfs_2(u+1,sum+w[u]);
}
int main()
{
cin >>W>>n;
k=n/2+2;
for(int i=0;i<n;i++) cin >>w[i];
sort(w,w+n);
reverse(w,w+n);
dfs_1(0,0);
sort(s,s+cnt);
reverse(s,s+cnt);
len=unique(s,s+cnt)-s;//去重
dfs_2(k,0);
cout <<ans<<endl;
}