Luogu 3423 [POI 2005]BAN-银行票据 (多重背包单调队列优化 + 方案打印)
题意:
给出 n 种纸币的面值以及数量,求最少使用多少张纸币能凑成 M 的面额。
细节:
好像是要输出方案,看来很是头疼啊。
分析:
多重背包,裸体???
咳咳,好吧需要低调,状态就出来了: dp [ i ] 表示面额为 i 最少需要多少张纸币组成。
转移:dp [ i ] = min ( dp [ i ] , dp [ i - w [ j ] × k ] + k ) ( k 表示当前纸币有几张,0 ≤ k ≤ num [ j ] 表示这类纸币的数量)
好了你就完成了此题的部分分,本人蒟蒻打死都想不到背包还能优化可是它显然可以。
所以开始向满分冲刺,对于上方的转移你显然不能优化,对于一个转移竟然跟三个变量有关,嘿嘿嘿,这个转移很有心机,
我们需要进行方程的转换,不妨先来看一下是否存在重复,假设当前 num [ j ] = 2,w [ 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 + 3,dp [ 2 ] - 2 + 3,dp [ 3 ] - 3 + 3 转移
i = 4 时,从 dp [ 2 ] - 2 + 4,dp [ 3 ] - 3 + 4,dp [ 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-银行票据 (多重背包单调队列优化 + 方案打印)的更多相关文章
- [BZOJ4182]Shopping (点分治+树上多重背包+单调队列优化)
[BZOJ4182]Shopping (点分治+树上多重背包+单调队列优化) 题面 马上就是小苗的生日了,为了给小苗准备礼物,小葱兴冲冲地来到了商店街.商店街有n个商店,并且它们之间的道路构成了一颗树 ...
- 【POJ1276】Cash Machine(多重背包单调队列优化)
大神博客转载http://www.cppblog.com/MatoNo1/archive/2011/07/05/150231.aspx多重背包的单调队列初中就知道了但一直没(不会)写二进制优化初中就写 ...
- hdu 2844 多重背包+单调队列优化
思路:把价值看做体积,而价值的大小还是其本身,那么只需判断1-m中的每个状态最大是否为自己,是就+1: #include<iostream> #include<algorithm&g ...
- poj1742 Coins(多重背包+单调队列优化)
/* 这题卡常数.... 二进制优化或者单调队列会被卡 必须+上个特判才能过QAQ 单调队列维护之前的钱数有几个能拼出来的 循环的时候以钱数为步长 如果队列超过c[i]就说明队头的不能再用了 拿出来 ...
- BZOJ.4182.Shopping(点分治/dsu on tree 树形依赖背包 多重背包 单调队列)
BZOJ 题目的限制即:给定一棵树,只能任选一个连通块然后做背包,且每个点上的物品至少取一个.求花费为\(m\)时最大价值. 令\(f[i][j]\)表示在点\(i\),已用体积为\(j\)的最大价值 ...
- bzoj 1531 Bank notes 多重背包/单调队列
多重背包二进制优化终于写了一次,注意j的边界条件啊,疯狂RE(还是自己太菜了啊啊)最辣的辣鸡 #include<bits/stdc++.h> using namespace std; in ...
- POJ 1742 Coins(多重背包, 单调队列)
Description People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar. ...
- 多重背包 /// 单调队列DP oj1943
题目大意: em.... 就是多重背包 挑战340页的东西 ...自己的笔记总结总是比较乱的 重点:原始的状态转移方程中 更新第 i 种物品时 重量%w[i] 的值不同 则它们之间是相互独立的: 1- ...
- Luogu 2569 [SCOI2010]股票交易 (朴素动规转移 + 单调队列优化)
题意: 已知未来 N 天的股票走势,第 i 天最多买进 as [ i ] 股每股 ap [ i ] 元,最多卖出 bs [ i ] 股每股 bp [ i ] 元,且每天最多拥有 Mp 股,且每两次交易 ...
随机推荐
- JAVA Debug调试技术
System.out.println(e),这个方法打印出异常,并且输出在哪里出现的异常,不过它和另外一个e.printStackTrace()方法不同.后者也是打印出异常,但是它还将显示出更深的调用 ...
- C. Divide by Three DP
http://codeforces.com/contest/792/problem/C 这题奇葩题我居然用dp过了. 如果要模拟的话,可以用一个栈保存,保存每一个%3 = 2的pos,%3 = 1的p ...
- 禁用和关闭ECSHOP缓存
ECSHOP的缓存机制从一定程度上可以减少ECSHOP反复读取数据库的几率,从而一定程度上降低服务器负担,提高访问速度. 但是启用缓存机制,对一些新手站长也有不利的地方.我就遇到很多新手站长经常问,我 ...
- Linux 安装reids
1.下载: wget http://download.redis.io/releases/redis-3.0.0.tar.gz 2.解压: .tar.gz 3.安装: cd /redis- make ...
- Chess 模拟
链接:http://acm.hdu.edu.cn/showproblem.php?pid=6114 Problem Description 車是中国象棋中的一种棋子,它能攻击同一行或同一列中没有其他棋 ...
- [转]AngularJS:何时应该使用Directive、Controller、Service?
AngularJS是一款非常强大的前端MVC框架.同时,它也引入了相当多的概念,这些概念我们可能不是太熟悉.(译者注:老外真谦虚,我大天朝的码农对这些概念那是相当熟悉啊!)这些概念有: Directi ...
- spring mvc添加静态资源访问时@Controller无效的解决
web.xml中的url-pattern设置为/,添加mvc:resources访问静态资源时,@Controller无效的问题 web.xml: <servlet> <servle ...
- 【实用】Html5实现文件异步上传
1 简介 开发文件上传功能从来不是一件愉快的事,异步上传更是如此,使用过iframe和Flash的上传方案,也都感觉十分的别扭.本文简要简绍利用Html5的FormData实现文件的异步上传,还可以实 ...
- Android笔记--Bitmap
Android | Bitmap解析 Android中Bitmap是对图像的一种抽象.通过他可以对相应的图像进行剪裁,旋转,压缩,缩放等操作.这里循序渐进的一步步了解Bitmap的相关内容. 先了解B ...
- 网页设计必备工具 firefox Web Developer插件 CSS工具组教程
该插件在火狐浏览器中安装.Web Developer 插件强大的功能超乎你的想象,用于CSS网页布局开发调试只是它强大功能的一部分,对于网络程序的开发也提供了非常强大的辅助设计功能,我们不将它完全的展 ...