zoukankan      html  css  js  c++  java
  • 中途相遇法 解决 超大背包问题 pack

    Description
    【题目描述】

    蛤布斯有n个物品和一个大小为m的背包,每个物品有大小和价值,它希望你帮它求出背包里最多能放下多少价值的物品。

    【输入数据】

    第一行两个整数n,m。接下来n行每行两个整数xi,wi,表示第i个物品的大小和价值。

    【输出数据】

    一行一个整数表示最大价值。

    【样例输入】

    5 100

    95 80

    4 18

    3 11

    99 100

    2 10

    【样例输出】

    101

    【数据范围】

    对于20%的数据,xi<=1500。

    对于另外30%的数据,wi<=1500。

    对于100%的数据,n<=40,0<=m<=10^18,0<=xi,wi<=10^15。


    中途相遇法这个东西比较有意思.
    这题接近于可行的办法就是暴搜, O(2 ^ n), 但是会炸掉.
    不难发现, 假如时间复杂度优化至O(2 ^ (n / 2)), 那么这题就是可以过的, 因此可以这样做:
    把所有物品分为左右两半, 2 ^ (n / 2)枚举在同一半中每一种选取物品方案(即从小到大枚举i)所得到的价值以及, 记录入L[i], R[i]中(通过i的二进制拆分来得到当前的具体方案).
    将L, R排序, 去掉那些空间大而价值小的方案, 扫一遍利用决策单调性即可得到答案.
    附上代码(跑得好慢…)

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxN = 40;
    struct item
    {
        long long size, val;
        item(){}
        item(long long first, long long second): size(first), val(second){}
    }a[maxN], L[1 << (maxN >> 1)], R[1 << (maxN >> 1)];
    int operator <(item x, item y)
    {
        if(x.size == y.size)
            return x.val > y.val;
        return x.size < y.size;
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("pack.in", "r", stdin);
        freopen("pack.out", "w", stdout);
        #endif
        ios::sync_with_stdio(false);
        long long n, m;
        cin >> n >> m;
        for(int i = 0; i < n; i ++)
            cin >> a[i].size >> a[i].val;
        int mid = n >> 1;
        for(int i = 0; i < 1 << (mid); i ++)
        {
            long long sizeSum = 0, valSum = 0;
            for(int j = 0; j < mid; j ++)
                if((i >> j) & 1)
                    sizeSum += a[j].size, valSum += a[j].val;
            L[i] = item(sizeSum, valSum);
        }
        sort(L, L + (1 << mid));
        long long cntL = 1;
        for(int i = 1; i < 1 << mid; i ++)
            if(L[cntL - 1].val < L[i].val)
                L[cntL ++] = L[i];
        for(int i = 0; i < 1 << (n - mid); i ++)
        {
            long long sizeSum = 0, valSum = 0;
            for(int j = 0; j < n - mid; j ++)
                if((i >> j) & 1)
                    sizeSum += a[mid + j].size, valSum += a[mid + j].val;
            R[i] = item(sizeSum, valSum);
        }
        sort(R, R + (1 << (n - mid)));
        long long cntR = 1;
        for(int i = 1; i < 1 << (n - mid); i ++)
            if(R[cntR - 1].val < R[i].val)
                R[cntR ++] = R[i];
        long long p = 0, q = cntR - 1;
        long long ans = 0;
        for(int p = 0; p < cntL; p ++)
        {
            while(L[p].size + R[q].size > m && q)
                q --;
            if(L[p].size + R[q].size > m)
                continue;
            ans = max(ans, L[p].val + R[q].val);
        }
        cout << ans;
    }
  • 相关阅读:
    Oracle 存储过程_(收集)
    Oracle job procedure 存储过程定时任务(转自hoojo)
    windows环境下,Jenkins的安装和基础配置
    如何使用IntelliJ IDEA 配置Maven
    在IntelliJ IDEA中安装Junit,TestNG
    JAVA 操作 properties 配置文件
    Java语法----Java中equals和==的区别(转载)
    由于网页点击速度过快,导致selenium无法定位到元素的问题
    使用IntelliJ idea运行selenium3.0
    selenium webdriver java环境配置
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/6402845.html
Copyright © 2011-2022 走看看