Bank notes
原题链接
这道题算是 P3423 的迷你版,没有输出每个硬币取了多少个,十分的友好。
描述
Byteotian Bit Bank (BBB) 拥有一套先进的货币系统,这个系统一共有种面值的硬币,面值分别为. 但是每种硬币有数量限制,现在我们想要凑出面值k求最少要用多少个硬币.
输入
第一行一个数接下来一行 个整数 , 第三行 个整数 , 表示每种硬币的个数.最后一行一个数表示要凑的面值数量, .
输出
第一行一个数表示最少需要付的硬币数
输入样例 1
3
2 3 5
2 2 1
10
输出样例 1
3
通过题目显然可以看出,这是一道明显的多重背包问题。
但是这个数据呢,显然不是很友好。按照一般的多重背包来说,时间复杂度显然为,最坏复杂度。很好,属实是炸到姥姥家了。
二进制拆分
这是对于多重背包的一种尤为有效的优化方法。
举个例子就明白:
例子
100件物品
怎么才能用最少的数枚举出来?
实际上可以通过组合的方式:
给出
1 2 4 8 16 32
分别二进制下的对应
1 10 100 1000 10000 100000
则可以枚举出1到63(1111111),再加上一个37,就可以实现1100的枚举。
用法
众所周知,背包问题有很多变种都是从01背包转过来的。01背包的特征:有选与不选两种状态。并且能通过枚举每种状态,求得最优解。
仔细思考一下,假设把100件物品分成二进制。价值,代价(如果有)就会增加到原来的同样数量的倍数,是不是就可以拿拆分后的数做01背包呢?
显然是的。
使用了二进制拆分后的复杂度为:
最大时间约为:,可以通过。
#include<bits/stdc++.h>
using namespace std;
int n,m,b[211],c[211],dp[2111111],w[111111],v[111111];
int main(){
freopen("bank.in","r",stdin);
freopen("bank.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++) {
scanf("%d",&b[i]);
}
for(int i=1;i<=n;i++) {
scanf("%d",&c[i]);
}
int cnt=0;
for(int i=1;i<=n;i++) {
int count=1;
while(count<c[i]) {
cnt++;
w[cnt]=count*b[i];
v[cnt]=count;
c[i]-=count;
count*=2;
}
if(c[i]>0) {
cnt++;
w[cnt]=c[i]*b[i];
v[cnt]=c[i];
}
}
for(int i=1;i<=2000000;i++) {
dp[i]=0x7ffffff;
}
cin>>m;
for(int i=1;i<=cnt;i++) {
for(int j=m;j>=w[i];j--) {
dp[j]=min(dp[j],dp[j-w[i]]+v[i]);
}
}
cout<<dp[m];
return 0;
}
据说可以用单调队列优化,但我不会不想写。以后有时间再说吧。
等我成了大佬。
本文作者:cjrqwq
本文链接:https://www.cnblogs.com/yfzqwq/p/18492851
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!