题意:

给出 n 种纸币的面值以及数量,求最少使用多少张纸币能凑成 M 的面额。

细节:

好像是要输出方案,看来很是头疼啊。

分析:

多重背包,裸体???

咳咳,好吧需要低调,状态就出来了: dp [ i ] 表示面额为 i 最少需要多少张纸币组成。

转移:dp [ i ] = min ( dp [ i ] , dp [ i - w [ j ] × k ] + k ) ( k 表示当前纸币有几张,0 ≤ k ≤ num [ j ] 表示这类纸币的数量)

好了你就完成了此题的部分分,本人蒟蒻打死都想不到背包还能优化可是它显然可以。

所以开始向满分冲刺,对于上方的转移你显然不能优化,对于一个转移竟然跟三个变量有关,嘿嘿嘿,这个转移很有心机,

我们需要进行方程的转换,不妨先来看一下是否存在重复,假设当前 num [ j ] = 2w [ j ] = 1 时:

i = 3 时,可以从 3、2、1 进行转移

i = 4 时,可以从 4、3、2 进行转移

i = 5 时,可以从 5、4、3 进行转移

顿时豁然开朗,存在重复存在优化的可能性,但是却对应了不同的价值,比如 i = 3 时从 2 进行转移的花费为 1 ,但是对于 i = 4 来说花费就变成了 2 ,所以对于当前的第 j 层来说其转移的值是不定的,所以无法进行优化。

但如果先在转移之前每个值都减去 i 的话,就会出现这样的情况:

i = 3 时,从 dp [ 1 ] - 1 + 3dp [ 2 ] - 2 + 3dp [ 3 ] - 3 + 3 转移

i = 4 时,从 dp [ 2 ] - 2 + 4dp [ 3 ] - 3 + 4dp [ 4 ] - 4 + 4 转移

不然发现对于 i 来说其都加了 i ,但前方的转移都是相同的,这样就可以开始进一步的优化了。

不妨令 d = v [ i ],a = j / d,b = j % d ,即 j = a × d + b

这样方程就变化成了:dp [ j ] = min ( dp [ b + k × d] - k )+ a

所以只需要维护一个关于 dp [ b + k × d ] - k 单调递增的队列即可。

最后我们再来考虑一下如何打印出最后的方案,其实只需要记录每个转移是从哪一个面额而来的以及它当前用了哪一种面额的纸币即可,且这只是其中的一种方案。

代码:

#include<bits/stdc++.h>
#define MAXN 20005
using namespace std; struct Node{
int ans,W;
}que[MAXN];
int n, m, w[MAXN], num[MAXN], f[MAXN], d[205][MAXN]; void print(int x, int y){ //打印方案
if (!x) return;
print(x-1, d[x][y]);
printf("%d ", (y-d[x][y])/w[x]);
} int main(){
scanf("%d", &n);
for (int i=1; i<=n; i++) scanf("%d", &w[i]);
for (int i=1; i<=n; i++) scanf("%d", &num[i]);
scanf("%d", &m);
memset(f, 0x3f3f3f, sizeof f);
f[0]=0;
for (int i=1; i<=n; i++){
for (int j=0; j<w[i]; j++){
int head=1, tail=0;
for (int k=j, cnt=0; k<=m; cnt++, k+=w[i]){
if (tail-head==num[i]) head++; //维护队首
int Ans=f[k]-cnt;
while (head<=tail && Ans<que[tail].ans) --tail; //维护队尾
que[++tail].ans=Ans, que[tail].W=k; //加入新的元素
f[k]=que[head].ans+cnt; //转移当前的最有状态
d[i][k]=que[head].W; //记录当前的最有转移从何而来
}
}
}
printf("%d\n", f[m]);
print(n, m); //打印方案
return 0;
}

小结:

可以把该类问题进行一般化的处理,也就是将方程转化为 dp [ i ] = min ( dp [ i ] , dp [ i - w [ j ] × k ] + k × v [ i ] ) 同理它可以转化为以下的式子:

假设 d = v [ i ],a = j / d,b = j % d,即 j = a × d + b

dp [ i ][ j ] = max { dp [ i - 1 ] [ b + k × d ] - k × w[i] } + a × w[i] (a – m[i] <= k <= a)

考虑用单调队列优化即可。Q A Q

Luogu 3423 [POI 2005]BAN-银行票据 (多重背包单调队列优化 + 方案打印)的更多相关文章

  1. [BZOJ4182]Shopping (点分治+树上多重背包+单调队列优化)

    [BZOJ4182]Shopping (点分治+树上多重背包+单调队列优化) 题面 马上就是小苗的生日了,为了给小苗准备礼物,小葱兴冲冲地来到了商店街.商店街有n个商店,并且它们之间的道路构成了一颗树 ...

  2. 【POJ1276】Cash Machine(多重背包单调队列优化)

    大神博客转载http://www.cppblog.com/MatoNo1/archive/2011/07/05/150231.aspx多重背包的单调队列初中就知道了但一直没(不会)写二进制优化初中就写 ...

  3. hdu 2844 多重背包+单调队列优化

    思路:把价值看做体积,而价值的大小还是其本身,那么只需判断1-m中的每个状态最大是否为自己,是就+1: #include<iostream> #include<algorithm&g ...

  4. poj1742 Coins(多重背包+单调队列优化)

    /* 这题卡常数.... 二进制优化或者单调队列会被卡 必须+上个特判才能过QAQ 单调队列维护之前的钱数有几个能拼出来的 循环的时候以钱数为步长 如果队列超过c[i]就说明队头的不能再用了 拿出来 ...

  5. BZOJ.4182.Shopping(点分治/dsu on tree 树形依赖背包 多重背包 单调队列)

    BZOJ 题目的限制即:给定一棵树,只能任选一个连通块然后做背包,且每个点上的物品至少取一个.求花费为\(m\)时最大价值. 令\(f[i][j]\)表示在点\(i\),已用体积为\(j\)的最大价值 ...

  6. bzoj 1531 Bank notes 多重背包/单调队列

    多重背包二进制优化终于写了一次,注意j的边界条件啊,疯狂RE(还是自己太菜了啊啊)最辣的辣鸡 #include<bits/stdc++.h> using namespace std; in ...

  7. POJ 1742 Coins(多重背包, 单调队列)

    Description People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar. ...

  8. 多重背包 /// 单调队列DP oj1943

    题目大意: em.... 就是多重背包 挑战340页的东西 ...自己的笔记总结总是比较乱的 重点:原始的状态转移方程中 更新第 i 种物品时 重量%w[i] 的值不同 则它们之间是相互独立的: 1- ...

  9. Luogu 2569 [SCOI2010]股票交易 (朴素动规转移 + 单调队列优化)

    题意: 已知未来 N 天的股票走势,第 i 天最多买进 as [ i ] 股每股 ap [ i ] 元,最多卖出 bs [ i ] 股每股 bp [ i ] 元,且每天最多拥有 Mp 股,且每两次交易 ...

随机推荐

  1. 洛谷 P4137 Rmq Problem / mex

    https://www.luogu.org/problemnew/show/P4137 只会log^2的带修主席树.. 看了题解,发现有高妙的一个log做法:权值线段树上,设数i对应的值ma[i]为数 ...

  2. Problem D. What a Beautiful Lake dp

    Problem D. What a Beautiful Lake Description Weiming Lake, also named "Un-named Lake", is ...

  3. Function ereg() is deprecated in

    PHP 5.3 ereg() 无法正常使用,提示"Function ereg() is deprecated Error".问题根源是php中有两种正则表示方法,一个是posix, ...

  4. .Net 遍历目录下第一层的子文件夹和子文件夹里的文件

    今天再完成一道任务的时候需要遍历得到所有txt文件,搜索很久终于得到了一个很方便的方法. foreach (string o in Directory.GetDirectories(@"D: ...

  5. SpringBoot学习笔记-Chapter2(hello word)

    开篇 第一次在博客园上写博客,初衷是想记录一下学习笔记,以往都是用笔去记录下学习笔记,现在来看在效率.检索速度上以及可可复制性都不好.作为一名Java开发人员 不会Spring Boot一定会被鄙视的 ...

  6. jQuery的基本使用及选择器和筛选器

    回顾 事件 鼠标clickdblclickcontextmenumouseentermouseleavemousemovemousedownmouseup​键盘keydownkeyupkeypress ...

  7. (转)ASIC设计中各个阶段需要注意的问题——节选

    ASIC 的复杂性不断提高,同时工艺在不断地改进,如何在较短的时间内开发一个稳定的可重用的ASIC芯片的设计,并且一次性流片成功,这需要一个成熟的ASIC 的设计方法和开发流程.本文结合NCveril ...

  8. 源文件名长度大于系统支持的长度,无法删除,java主方法执行方式删除

    import java.io.File; /** * @author 海盗船长 * 2017年2月14日11:24:26 */ public class DeleteFiles { public st ...

  9. shell框架

    #!/bin/bash#注释#注释#环境变量相关,如下PATH=/sbin:/bin:/usr/bin:/usr/sbin #引入库函数,如下,类似于c语言的#include "*.h&qu ...

  10. SAP C/4HANA到底包含哪些产品?

    2018年6月的SAPPHIRE(蓝宝石大会)上, SAP发布了新的商务软件套件:C/4HANA,意在通过SAP C/4HANA将前台应用和SAP Digital Core(数字化核心)S/4HANA ...