背包真假专题

Posted spare-no-effort

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了背包真假专题相关的知识,希望对你有一定的参考价值。

前言

传统意义上的背包是有一些众所周知的定义和判断性质的
(n)件物品,每件物品有价值、体积、数量(1个、无限、规定数量)等属性(一般就是这三个),彼此可能存在依赖或排斥,现在要把它们尽量放入一个容积为(m)的背包里,问获得的最大价值
然后主要分为01背包、完全背包、多重背包等(比如还有混合背包(前三个总和)、二维费用背包、分组背包等)

01背包:时间复杂度(O(nm)),空间复杂度(O(m))

完全背包:时间复杂度(O(nm)),空间复杂度(O(m))

多重背包:时间复杂度(O(nmsum cnt)),空间复杂度(O(m)),二进制优化时间复杂度变成(O(nmlog sum cnt))

多重背包单调队列优化:时间复杂度(O(nm)),空间复杂度(O(m))

不管怎样,背包问题始终无法脱离时间复杂度(O(nm)),空间复杂度(O(m))的框框吧(至少我现在是这么认为的)

那么对于(n,m)超过(10000)很有可能并不是背包。

而且注意背包问题是不能够贪心的,除了部分背包(可以塞一部分当然按性价比排序,它也不属于背包)

然后一旦题目的模型可以转换成背包,可以暗暗庆幸——又是道思维题(然而我连模型转换都不会,我太菜了)


CF3B Lorry

题目

(n(1leq nleq 10^5))件物品,每件物品有自身的价值((leq 10^4))和体积(1或2),背包大小为(m(1leq mleq 10^9)),问可获得的最大价值,并输出其中一种方案(所选每件物品的编号)


分析

背包真假鉴定:假(时空都不允许)

考虑给的限制,体积为1或2,那只能是贪心,但是怎么贪,

首先肯定选价值大的,有体积的影响就分别降序排序

如果选了若干个体积为1的,那么肯定剩下全部用体积为2的填(反过来同理)

所以可以排序后将体积为2的弄成前缀和,那么我选了价值最大的一部分体积为1的物品,再用( ext{if})判断填完体积2的答案会不会更好,再标记选择的编号

所以就是一道妥妥的贪心题


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
struct rec{
    int w,rk;
    bool operator <(const rec &t)const{
         return w>t.w;
    }
}c1[100011],c2[100011];
int n,m,n1,n2,s[1000011],ans,p1,p2;
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans; 
}
inline void print(int ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
signed main(){
    n=iut(),m=iut();
    for (rr int i=1;i<=n;++i){
        rr int x=iut(),y=iut();
        if (x==1) c1[++n1]=(rec){y,i};
            else c2[++n2]=(rec){y,i};
    }
    sort(c1+1,c1+1+n1),sort(c2+1,c2+1+n2);
    for (rr int i=1;i<=n2;++i) s[i]=s[i-1]+c2[i].w;
    for (rr int i=0,sum=0;i<=n1;++i){
        rr int now=(m-i)>>1; sum+=c1[i].w;
        if (now<0) break; if (now>n2) now=n2;
        if (sum+s[now]>ans) ans=sum+s[now],p1=i,p2=now;
    }
    print(ans),putchar(10);
    for (rr int i=1;i<=p1;++i) print(c1[i].rk),putchar(32);
    for (rr int i=1;i<=p2;++i) print(c2[i].rk),putchar(32);
    return 0;
} 

未完待续

以上是关于背包真假专题的主要内容,如果未能解决你的问题,请参考以下文章

背包专题G - Dividing hdu 1059多重背包

背包专题 D - Coins hdu2844多重背包

背包专题C - The trouble of Xiaoqian hdu3591混合背包:多重背包+完全背包

背包DP专题

动态规划专题之背包问题

背包专题F - Ahui Writes Word hdu373201背包+二进制优化