背包真假专题
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;
}
未完待续
以上是关于背包真假专题的主要内容,如果未能解决你的问题,请参考以下文章