AcWing 171. 送礼物 (双向DFS)

整理的算法模板: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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值