AcWing 171. 送礼物

原题链接

考察:双向搜索dfs

思路:

        很像背包模型,但是用背包TLE.这道题N<=46,不能用背包就可以考虑搜索,如果普通的爆搜时间复杂度是O(2n),也会TLE,需要优化.爆搜常考虑的优化有迭代加深,但是W太大不考虑.还有就是双向dfs,适用于终态和初态明确的情况下.这道题的终态需要一点思维,我们将物品对半分,初态的dfs搜索前半部分,终态的dfs可以枚举后半部分的重量,然后找当前重量S+?<=W的最大值.数组里找符合某条件的最大值,多用于二分.这样的时间复杂度是223+223*log2223 = 223+223*23.为了压时间复杂度,我们可以把式子的左半部分放大一点,右边再乘一个数就可以和左边均衡.

        总体思路确定,接下来考虑剪枝.很明显搜索顺序是从大到小.然后冗余情况考虑组合枚举.顺便这里进行set判重反而可能会TLE.用数组存储搜索完了再去重反而更快....

注意:int在计算时有爆掉风险

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <set>
 5 using namespace std;
 6 typedef long long LL;
 7 const int N = 50,M = 25;
 8 int w[N],m,n,k,weigh[(1<<M)+10],cnt,ans;
 9 void dfs(int now,int idx)
10 {
11     if((LL)now+w[k]>m) return;
12     weigh[cnt++] = now;
13     for(int i=idx;i<=k;i++)
14        if((LL)w[i]+now<=m) dfs(now+w[i],i+1);
15 }
16 void dfs_2(int now,int st)
17 {
18     if((LL)now+weigh[1]>m) return;
19     int l = 0,r = cnt-1;
20     while(l<r)
21     {
22         int mid = l+r+1>>1;
23         if((LL)now+weigh[mid]<=m) l = mid;
24         else r = mid-1;
25     }
26     if((LL)now+weigh[r]>ans) ans = now+weigh[r];
27     for(int i=st;i<=n;i++)
28       if((LL)w[i]+now<=m) dfs_2(now+w[i],i+1);
29 }
30 int main()
31 {
32     scanf("%d%d",&m,&n);
33     for(int i=1;i<=n;i++) scanf("%d",&w[i]);
34     sort(w+1,w+n+1);
35     reverse(w+1,w+n+1);
36     k = n/2+2;
37     dfs(0,1);
38     sort(weigh,weigh+cnt);
39     cnt = unique(weigh,weigh+cnt)-weigh;
40     dfs_2(0,k+1);
41     printf("%d\n",ans);
42     return 0;
43 }

 

posted @ 2021-04-19 19:46  acmloser  阅读(54)  评论(0编辑  收藏  举报