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 股,且每两次交易 ...
随机推荐
- IIS7文件无法下载问题处理
使用IIS建立了静态站点,内部放置了一些文件供内部局域网下载使用,但deb等文件格式无法下载. 解决办法: 1.在IIS管理器中点击站点,选择右侧的MIME类型. 2.在MIME类型中添加需要下载文件 ...
- springJDBC 事物隔离
五.Spring-jdbc的实现 第一步:导jar包 pom.xml <!--引入spring-beans节点--><dependency> <groupId> ...
- 学习typescript(二)
学习typescript(二) ts 与 js 交互 ts 调用 js module使用 分为两种情况: ts 调用自己写的 js ts 调用别人写的 js 也就通过 npm 安装的 第一种情况处理如 ...
- react 父子传值
import React from 'react'; import ReactDOM from 'react-dom'; import $ from 'jquery'; //var $ = requi ...
- Mybatis中的复合条件查询
1.Map中根据字段名存儲: 定义接口:List<Student> selectByCondition1(Map<String,Object> map); 映射文件: < ...
- 打造自己的JavaScript武器库
自己打造一把趁手的武器,高效率完成前端业务代码. 前言 作为战斗在业务一线的前端,要想少加班,就要想办法提高工作效率.这里提一个小点,我们在业务开发过程中,经常会重复用到日期格式化.url参数转对象. ...
- Easyui combobox如何默认选中第一项???
以下代码可以实现combobox默认选中第一项,在实际开发中我们可能会用到! // 处理combobox默认选中的问题 <input id="user_type" class ...
- Android的Activity之间传对象的方法
传值代码块 //Serializeable传递对象的方法 public void SerializeMethod(){ Person mPerson = new Person(); mPerson.s ...
- 机器学习之 PCA (二)
参考 http://www.cnblogs.com/frombeijingwithlove/p/5931872.html
- 2017四川省赛E题( Longest Increasing Subsequence)
提交地址: https://www.icpc-camp.org/contests/4rgOTH2MbOau7Z 题意: 给出一个整数数组,F[i]定义为以i结尾的最长上升子序列,然后问以此删除掉第i个 ...