背包真假专题

余生颓废 提交于 2020-01-29 23:01:08

前言

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

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

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

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

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

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

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

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

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


CF3B Lorry

题目

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


分析

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

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

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

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

所以可以排序后将体积为2的弄成前缀和,那么我选了价值最大的一部分体积为1的物品,再用\(\text{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;
} 

未完待续

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!