目录
前言
传统意义上的背包是有一些众所周知的定义和判断性质的
有\(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; }
未完待续
来源:https://www.cnblogs.com/Spare-No-Effort/p/12241565.html