【POJ1276】Cash Machine(多重背包单调队列优化)
大神博客转载http://www.cppblog.com/MatoNo1/archive/2011/07/05/150231.aspx
多重背包的单调队列初中就知道了但一直没(不会)写
二进制优化初中就写过
一直不写会心虚就写一下这个吧
朴素方程
dp[i,j]=max(dp[i-1,j-w[i]*k]+c[i]*k) w[i]*k<=j k<=j div w[i]
忽略第一维
dp[j]=max(dp[j-w[i]*k]+c[i]*k)
复杂度O(m2n)
以下是大神原文:
将决策下标按照模w0的余数进行分类,可以分成w0类,分别对应模w0余0、余1……余(w0-1)的情况。这时,上面方程中的所有决策下标j-x*w0都是同一类的。进一步,设q =j/w0(下取整),r=j%w0,则j=q*w0+r,对于某个决策下标j',设k=(j'-r)/w0,即j'=k*w0+r。显然可以发现,k的取值范围是:k>=0且q-s0<=k<=q,也即k的下界是max{0, q-s0}——随j的单调而单调。
然后,转移方程可以改为(这里把r当成一个已知量了):
F[q*w0+r] = max{F[k*w0+r]+(q-k)*v0} (k>=0且q-s0<=k<=q)
即F[q*w0+r]=max{F[k*w0+r]-k*v0}+q*v0 (k>=0且q-s0<=k<=q)
设G[k]=F[k*w0+r]得:
G[q]=max{G[k]-k*v0}+q*v0 (k>=0且q-s0<=k<=q)
这个方程已经可以使用单调队列来优化了!
这样可以得出算法:
(1)从1到n,枚举i,建立w[i]个空的单调队列,每个队列的元素都是两个int值:(k, val),表示转换后下标和决策值(G[k]-k*v[i]);
(2)从0到m,枚举j,得出q、r的值,对于队列r:
【1】删去队首过时(k<q-m[i])的元素;
【2】F[j]入队(这里的F[j]指上一阶段的F[j],即F[i-1][j]。因此这一步操作一定要先进行),删去队尾所有决策值val不大于(F[j]-q*v[i])的元素。
【3】取出队首结点,其val值加上q*v[i]后即为本阶段F[j]的值。
最后F[m]即为结果。总时间复杂度为O(NM)。
其实这个是可以推广的,即对于如下形式的转移方程(其中H、G和W均为常量,B[i]为决策下标的下界,随i单调):
F[i] = opt{F[i-x*H+W]}+G (B[i]<=i-x*H+W<i,x∈N)
都可以用上述的办法进行转化,从而进行单调队列优化。
我自己的萎靡过程:
形如dp[i]=max(dp[j]+cost(j+1,i))+M,cost具有单调性的DP可以用单调队列优化
我们尝试转化它的形式
dp[j]=max(dp[j-w[i]*1]+c[i]*1,dp[j-w[i]*2]+c[i]*2])……
设k<j<i,i-j,i-k能整除w[i],显然j-k也可以
dp[j]+c[i]*(i-j)/w[i]>dp[k]+c[i]*(i-k)/w[i]
dp[j]-dp[k]>c[i]*(i-k-i+j)/w[i]
dp[j]-dp[k]>c[i]*(j-k)/w[i]
好像很麻烦的样子
好吧还是学大神的做法吧
设j=w[i]*k+r,r=j mod w[i]
dp[w[i]*k+r]=max(dp[w[i]*(k-x)+r]+c[i]*x)
设x>y,dp[w[i]*x+r]+c[i]*x>dp[w[i]*y+r]+c[i]*y
dp[w[i]*x+r]-dp[w[i]*y+r]>c[i]*(y-x)
(dp[w[i]*x+r]-dp[w[i]*y+r])/(y-x)>c[i]对于单个i成立
我们对于每个j计算出它对于每个i时的max x与r O(mn)
之后就可以用单调队列的思路做了
POJ上一直RE不知道怎么回事搞得我都不知道对不对
自己的对拍好像没有问题
哪位找到错误提醒下谢谢
一些奇奇怪怪的if 判 a[i] k 什么的 不加会有奇奇怪怪的错误
显然空间不够必须滚动队列
POJ空间也卡 格式也卡
懒得改了 反正没什么乱用
var q:array[..,..,..]of longint;
f:array[..,..]of longint;
t,w:array[..]of longint;
a,ww,cc:array[..]of longint;
m,n,i,j,k,r,t1,w1,tmp,ans,v:longint; begin
assign(input,'1.in'); reset(input);
assign(output,'1.out'); rewrite(output);
while not eof do
begin
read(m,n);
if (m=)and(n=) then break;
for i:= to n do
begin
read(a[i],ww[i]);
cc[i]:=ww[i];
if a[i]>m div ww[i] then a[i]:=m div ww[i];
end;
fillchar(f,sizeof(f),); ans:=;
for i:= to n do
if a[i]> then
begin
v:=-v;
fillchar(q,sizeof(q),);
for j:= to m do f[v,j]:=f[-v,j];
for j:= to ww[i]- do begin w[j]:=; t[j]:=; end;
for j:= to m do
begin
k:=j div ww[i];
if k>a[i] then continue; r:=j mod ww[i];
inc(w[r]); q[r,w[r] mod ,]:=k; q[r,w[r] mod ,]:=f[-v,j]-k*ww[i];
end; for j:= to m do
begin
k:=j div ww[i]; r:=j mod ww[i];
t1:=t[r]; w1:=w[r];
while (w1-t1>=)and(k-q[r,t1 mod ,]>a[i]) do
begin
inc(t[r]); inc(t1);
end; tmp:=q[r,t1 mod ,]+cc[i]*k;
if tmp>ans then ans:=tmp;
if tmp>f[v,j] then f[v,j]:=tmp; while (w1-t1>=)and(q[r,w1 mod ,]<=f[-v,j]-k*ww[i]) do
begin dec(w[r]); dec(w1); end;
inc(w[r]); inc(w1); q[r,w1 mod ,]:=k; q[r,w1 mod ,]:=f[-v,j]-k*ww[i]; end;
end;
writeln(ans); end;
close(input);
close(output);
end.
【POJ1276】Cash Machine(多重背包单调队列优化)的更多相关文章
- [BZOJ4182]Shopping (点分治+树上多重背包+单调队列优化)
[BZOJ4182]Shopping (点分治+树上多重背包+单调队列优化) 题面 马上就是小苗的生日了,为了给小苗准备礼物,小葱兴冲冲地来到了商店街.商店街有n个商店,并且它们之间的道路构成了一颗树 ...
- POJ-1276 Cash Machine 多重背包 二进制优化
题目链接:https://cn.vjudge.net/problem/POJ-1276 题意 懒得写了自己去看好了,困了赶紧写完这个回宿舍睡觉,明早还要考试. 思路 多重背包的二进制优化. 思路是将n ...
- Luogu 3423 [POI 2005]BAN-银行票据 (多重背包单调队列优化 + 方案打印)
题意: 给出 n 种纸币的面值以及数量,求最少使用多少张纸币能凑成 M 的面额. 细节: 好像是要输出方案,看来很是头疼啊. 分析: 多重背包,裸体??? 咳咳,好吧需要低调,状态就出来了: dp [ ...
- POJ1276 - Cash Machine(多重背包)
题目大意 给定一个容量为M的背包以及n种物品,每种物品有一个体积和数量,要求你用这些物品尽量的装满背包 题解 就是多重背包~~~~用二进制优化了一下,就是把每种物品的数量cnt拆成由几个数组成,1,2 ...
- POJ 1276 Cash Machine(多重背包的二进制优化)
题目网址:http://poj.org/problem?id=1276 思路: 很明显是多重背包,把总金额看作是背包的容量. 刚开始是想把单个金额当做一个物品,用三层循环来 转换成01背包来做.T了… ...
- poj1742 Coins(多重背包+单调队列优化)
/* 这题卡常数.... 二进制优化或者单调队列会被卡 必须+上个特判才能过QAQ 单调队列维护之前的钱数有几个能拼出来的 循环的时候以钱数为步长 如果队列超过c[i]就说明队头的不能再用了 拿出来 ...
- POJ1276:Cash Machine(多重背包)
题目:http://poj.org/problem?id=1276 多重背包模板题,没什么好说的,但是必须利用二进制的思想来求,否则会超时,二进制的思想在之前的博客了有介绍,在这里就不多说了. #in ...
- hdu 2844 多重背包+单调队列优化
思路:把价值看做体积,而价值的大小还是其本身,那么只需判断1-m中的每个状态最大是否为自己,是就+1: #include<iostream> #include<algorithm&g ...
- BZOJ.4182.Shopping(点分治/dsu on tree 树形依赖背包 多重背包 单调队列)
BZOJ 题目的限制即:给定一棵树,只能任选一个连通块然后做背包,且每个点上的物品至少取一个.求花费为\(m\)时最大价值. 令\(f[i][j]\)表示在点\(i\),已用体积为\(j\)的最大价值 ...
随机推荐
- lua调用java过程
在cocos2dx框架中,有继承好的luaj文件来方便我们去使用lua调用java底层代码,注意:luaj只能使用在安卓平台下,如果在平台下使用,会出错, 所以使用前需要加平台判断,方法 如下: lo ...
- iOS跳转到各种系统设置界面
定位服务 定位服务有很多APP都有,如果用户关闭了定位,那么,我们在APP里面可以提示用户打开定位服务.点击到设置界面设置,直接跳到定位服务设置界面.代码如下: //定位服务设置界面 NSURL *u ...
- 标准C++(3)重载
一.函数的重载 c++中同一作用域下能够定义同名的函数(这就叫重载),但必须满足如下要求: 1.函数的参数列表必须不同,可以使参数数量不同,也可以使参数的类型不同,甚至是参数的顺序不同. 2.函数的返 ...
- Python爬虫系列-Selenium+Chrome/PhantomJS爬取淘宝美食
1.搜索关键字 利用Selenium驱动浏览器搜索关键字,得到查询后的商品列表 2.分析页码并翻页 得到商品页码数,模拟翻页,得到后续页面的商品列表 3.分析提取商品内容 利用PyQuery分析源码, ...
- vue-cli webpack配置cdn路径 以及 上线之后的字体文件跨域处理
昨天搞了一下vue项目打包之后静态资源走阿里云cdn. 配置了半天,终于找到了设置的地方 config/index.js 里面设置build 下的 assetsPublicPath 打包的时候便可以添 ...
- hdu-1231 连续最大子序列(动态规划)
Time limit1000 ms Memory limit32768 kB 给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj ...
- Nordic Collegiate Programming Contest 2015 D. Disastrous Downtime
You're investigating what happened when one of your computer systems recently broke down. So far you ...
- C++ 虚函数&纯虚函数&抽象类&接口&虚基类(转)
http://www.cnblogs.com/fly1988happy/archive/2012/09/25/2701237.html 1. 多态 在面向对象语言中,接口的多种不同实现方式即为多态.多 ...
- POJ-3278 广度优先搜索入门
#include<stdio.h> #include<stdlib.h> struct node{ int x; int s; }s[]; int main(){ ]={}; ...
- Hive学习笔记(二)
Hive内部表跟外部表之间的区别 创建外部表 先删除上面创建的表,指定location 此时在hdfs根目录下就有一个hivedata文件夹 上传文本数据到hivedata目录下 查询表中数据 删除上 ...