zoukankan      html  css  js  c++  java
  • 2401 送礼物 (双向搜索)

    描述

    作为惩罚,GY被遣送去帮助某神牛给女生送礼物(GY:貌似是个好差事)但是在GY看到礼物之后,他就不这么认为了。某神牛有N个礼物,且异常沉重,但是GY的力气也异常的大(-_-b),他一次可以搬动重量和在w(w<=2^31-1)以下的任意多个物品。GY希望一次搬掉尽量重的一些物品,请你告诉他在他的力气范围内一次性能搬动的最大重量是多少。

    输入格式

    第一行两个整数,分别代表W和N。
    以后N行,每行一个正整数表示G[i],G[i]<= 2^31-1。

    输出格式

    仅一个整数,表示GY在他的力气范围内一次性能搬动的最大重量。

    样例输入

    20 5
    7
    5
    4
    18
    1
    

    样例输出

    19
    

    数据范围与约定

      • 对于20%的数据 N<=26
        对于40%的数据 W<=2^26
        对于100%的数据 N<=45 W<=2^31-1

    思路: 这个题其实如果W小一点就是个简单的01背包,但是这个W到了2e9,空间太大没法dp

    那么就可以考虑枚举,也就是搜索,dfs的复杂度时2n,也就是说最高到245,这也很大了,但是我们可以将所有物品分成两份,分别枚举每份中可以组成的重量,然后对于其中一份的中每个重量t,在另一份中二分查找W-t,保存最大值。

    这就说双向dfs了,也就是让复杂度变成了 O(N*2n/2

    另附lower_bound注释,如果数组是从小到大排序,使用lower_bound,就是在数组中查到最小的大于等于num的数:

              如果数组是从大到小排序,lower_bound(ans+1,ans+1+n,num,greater<int>()) 要在其中加入greater<int>(),查找最大的小于等于num的数

    #include<bits/stdc++.h>
    using namespace std;
    
    int W,N;
    int weight[55];
    int ans1[9000000];
    int ans2[9000000];
    int cnt;
    void dfs(int now,int lim,int ans[],long long val)
    {
        if(val > W)return;
        if(now > lim)
        {
            ans[++cnt] = val;
            return;
        }
        dfs(now+1,lim,ans,val);
        dfs(now+1,lim,ans,val+weight[now]);
    }
    
    int main()
    {
        scanf("%d%d",&W,&N);
        for(int i=1;i<=N;i++)
        {
            scanf("%d",&weight[i]);
        }
        sort(weight+1,weight+1+N);
        reverse(weight+1,weight+1+N);
        int mid = (N+1)>>1;
        cnt = 0;
        dfs(1,mid,ans1,0);
        int cnt1 = cnt;
        cnt = 0;
        dfs(mid+1,N,ans2,0);
        int cnt2 = cnt;
        sort(ans1+1,ans1+1+cnt1);
        sort(ans2+1,ans2+1+cnt2);
        cnt1 = unique(ans1+1,ans1+1+cnt1) - ans1-1;
        cnt2 = unique(ans2+1,ans2+1+cnt2) - ans2-1;
        reverse(ans2+1,ans2+1+cnt2);
        int ans = 0;
        for(int i=1;i<=cnt1;i++)
        {
            if(ans1[i] > W)break;
            int pos = lower_bound(ans2+1,ans2+1+cnt2,W-ans1[i],greater<int>()) - ans2;
            ans = max(ans,ans1[i] + ans2[pos]);
        }
        printf("%d
    ",ans);
    }
    View Code
  • 相关阅读:
    Android-TabLayout设置内容宽度以及下划线宽度
    RecyclerView 上拉加载下拉刷新
    Android自定义View实现仿QQ实现运动步数效果
    Android开发中常见的内存泄露案例以及解决方法总结
    Android封装TitleBar基本适用所有常规开发
    Activity设置背景透明之开发坑
    Android表情开发
    订制EditText光标
    Android:java.lang.OutOfMemoryError:GC overhead limit exceeded
    Android之自定义View学习(一)
  • 原文地址:https://www.cnblogs.com/iwannabe/p/10588550.html
Copyright © 2011-2022 走看看