• 超大背包问题


    超大背包问题:有n个重量和价值分别为w[i]和v[i]的物品,从这些物品中挑选总重量不超过W的物品,求所有挑选方案中价值总和的最大值。其中,1 ≤ n ≤ 40, 1 ≤ w[i], v[i] ≤ 10^15, 1 ≤ W ≤ 10^15.

    按照普通的DP 思路显然是无法求解的, 背包的体积太大了, 那么就要换种思考的方向,观察物品的数量只有 40 个,普通的枚举话 2 ^ 40,肯定是超时,那么如何是分成两堆呢 ? 在按照字典序去枚举,不就没问题了吗 ?

    int n, W;
    int v[50], w[50];
    
    struct node
    {
        int ww, vv;
        node(int _w = 0, int _v = 0):ww(_w), vv(_v){}
        
    }pre[1<<25];
    
    bool cmp(node a, node b){
        if (a.vv == b.vv) return a.ww > b.ww;
        else return a.vv < b.vv;
    }
    int ans;
    
    int fun(int l, int r, int key){
        while(l <= r){
            int mid = (l + r) >> 1;
            if (pre[mid].vv == key) return pre[mid].ww;
            else if (pre[mid].vv < key) l = mid + 1;
            else r = mid - 1;
        }
        return pre[r].ww;
    }
    
    void solve(){
        int n2 = n / 2;
        for(int i = 0; i < 1 << n2; i++){
            int sv = 0, sw = 0;
            for(int j = 0; j < n2; j++){
                if ((i >> j) & 1){
                    sw += w[j];
                    sv += v[j];
                }
            }
            pre[i] = node(sw, sv);    
        }
        sort(pre, pre+ (1 << n2), cmp);
        int m = 0;
        for(int i = 1; i < 1<<n2; i++){
            if (pre[m].ww < pre[i].ww){
                pre[++m] = pre[i];
            }
        }
        ans = 0;
        for(int i = 0; i < 1<<(n-n2); i++){
            int sv = 0, sw = 0;
            for(int j = 0; j < (n-n2); j++){
                if ((i >> j) & 1){
                    sw += w[n2+j];
                    sv += v[n2+j];
                }
            }
            if (sv <= W){         
                int f = fun(0, m, W-sv);
                ans = max(ans, f + sw); 
            }
        }
    }
    
    int main() {
        //freopen("in.txt", "r", stdin);
        //freopen("out.txt", "w", sttout);
        
        while(~scanf("%d%d", &n, &W)){
            for(int i = 0; i < n; i++){
                scanf("%d%d", &v[i], &w[i]);
            }
            solve();
            printf("%d
    ", ans);
        }
        return 0;
    }
    /*
    4 5
    2 3
    1 2
    3 4
    2 2
    */
    
    东北日出西边雨 道是无情却有情
  • 相关阅读:
    函数式编程
    scala 有 + 运算符吗?
    使用 Idea 打 scala程序的 jar 包
    相见恨晚的 scala
    半夜思考,为什么 String 具有不变性
    我的常用
    DataTable学习笔记
    Js 操作cookie
    嵌套的 ajax 请求
    Jquery插件收集【m了慢慢学】
  • 原文地址:https://www.cnblogs.com/ccut-ry/p/7861956.html
Copyright © 2020-2023  润新知