博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【单调队列】【P1776】宝物筛选
阅读量:5699 次
发布时间:2019-06-17

本文共 2736 字,大约阅读时间需要 9 分钟。

Description

终于,破解了千年的难题。小FF找到了王室的宝物室,里面堆满了无数价值连城的宝物……这下小FF可发财了,嘎嘎。但是这里的宝物实在是太多了,小FF的采集车似乎装不下那么多宝物。看来小FF只能含泪舍弃其中的一部分宝物了……小FF对洞穴里的宝物进行了整理,他发现每样宝物都有一件或者多件。他粗略估算了下每样宝物的价值,之后开始了宝物筛选工作:小FF有一个最大载重为\(W\)的采集车,洞穴里总共有n种宝物,每种宝物的价值为\(v_i\),重量为\(w_i\),每种宝物有\(m_i\)件。小FF希望在采集车不超载的前提下,选择一些宝物装进采集车,使得它们的价值和最大。

Input

第一行为一个整数\(N\)\(w\),分别表示宝物种数和采集车的最大载重。

接下来\(n\)行每行三个整数,其中第\(i\)行第一个数表示第\(i\)类品价值,第二个整数表示一件该类物品的重量,第三个整数为该类物品数量。

Output

输出仅一个整数\(ans\),表示在采集车不超载的情况下收集的宝物的最大价值。

Sample Input

4 203 9 35 9 19 4 28 1 3

Sample Output

47

Hint

\(1~\leq~n~\leq~100\)

\(1~\leq~w~\leq~40000\)
数据保证合法

Solution

多重背包问题。设\(f_{i,j}\)是前\(i\)个物品重量是\(j\)的最大价值。考虑转移。朴素方法在转移时枚举该物品使用多少个。由于物品个数与\(w\)同阶,所以时间复杂度是\(O(nm^2)\),其中\(m\)代表最大载重量。

考虑优化。
考虑对第\(i\)个物品,重量为\(j\)时只能从\(j~-~k~\times~w_i\)转移。其中\(w\)代表重量。由于是连续转移,所以被转移的状态一定是单调不降的。考虑使用单调队列优化。
按照\(j~Mod~w_i\)分类,同一类之间才能转移,维护一群单调队列。每次判断出队时把队首元素加上在这个位置应该加的价值再与当前元素比较。

while((front <= end) && ((frog[pos][que[end]]+(k-que[end])/b*a)) <= frog[pos][k]) --end;

这里\(k\)是当前枚举到的背包重量。\(a\)是价值,\(b\)是该物品的重量。

同时,也可以不选择该物品,所以枚举所有重量与从上一行继承进行转移。

for(rg int j=1;j<=w;++j) frog[cur][j]=mmax(frog[cur][j],frog[pos][j]);

代码如下

Code

#include
#define rg register#define ci const int#define cl const long long inttypedef long long int ll;namespace IO { char buf[90];}template
inline void qr(T &x) { char ch=getchar(),lst=' '; while(ch>'9'||ch<'0') lst=ch,ch=getchar(); while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); if(lst=='-') x=-x;}template
inline void write(T x,const char aft,const bool pt) { if(x<0) x=-x,putchar('-'); int top=0; do { IO::buf[++top]=x%10+'0'; x/=10; } while(x); while(top) putchar(IO::buf[top--]); if(pt) putchar(aft);}template
inline T mmax(const T a,const T b) {if(a>b) return a;return b;}template
inline T mmin(const T a,const T b) {if(a
inline T mabs(const T a) {if(a<0) return -a;return a;}template
inline void mswap(T &a,T &b) { T temp=a;a=b;b=temp;}const int maxn = 110;const int maxm = 500010;int n,w,cur,pos=1,front,end,a,b,c,ans;int frog[2][maxm],que[maxm];int main() { qr(n);qr(w); for(rg int i=1;i<=n;++i) { a=b=c=0;qr(a);qr(b);qr(c); rg int upceil=b*c; for(rg int j=0;j
upceil)) ++front; while((front <= end) && ((frog[pos][que[end]]+(k-que[end])/b*a)) <= frog[pos][k]) --end; que[++end]=k; frog[cur][k]=frog[pos][que[front]]+(k-que[front])/b*a; } } for(rg int j=1;j<=w;++j) frog[cur][j]=mmax(frog[cur][j],frog[pos][j]); mswap(cur,pos); } for(rg int i=1;i<=w;++i) ans=mmax(ans,frog[pos][i]); write(ans,'\n',true); return 0;}

Summary

在使用手写队列时,初始化\(que[front=end=1]=0\)。判断队列不为空的条件是\(front ~\leq~end\)

转载于:https://www.cnblogs.com/yifusuyi/p/9603318.html

你可能感兴趣的文章
[Asp.Net web api]基于自定义Filter的安全认证
查看>>
洛谷P3763 [TJOI2017]DNA(后缀自动机)
查看>>
确定当前记录和下一条记录之间相差的天数
查看>>
NYOJ32:组合数(DFS入门)
查看>>
使用Callable和Future接口创建线程
查看>>
BZOJ 2568 比特集合
查看>>
sql语句返回主键SCOPE_IDENTITY()
查看>>
MongoDB培训
查看>>
机器学习开源项目精选TOP30
查看>>
python基础===对字符串进行左右中对齐
查看>>
例题7-1 UVa725 Division(枚举)
查看>>
第二十九课:javascript异步处理
查看>>
查看SQL数据库表占用空间
查看>>
I.MX6 U-boot编译找不到用户目录
查看>>
xml基础
查看>>
C#_无边框窗体和后台创建控件
查看>>
最炫民族风70个版本大合集
查看>>
LCX端口转发实现内网突破
查看>>
centos 6.5安装erlang和RabbitMQ
查看>>
CentOS7下使用NFS文件共享给Window server 2012
查看>>