【一本通OJ 1601:【例 5】Banknotes】题解
题目链接
题目
原题来自:POI 2005
Byteotian Bit Bank (BBB) 拥有一套先进的货币系统,这个系统一共有 种面值的硬币,面值分别为 。但是每种硬币有数量限制,现在我们想要凑出面值 ,求最少要用多少个硬币。
思路
首先不考虑时间复杂度,这个问题应该是可以用多重背包求解的。
同时,我们也可以把每种面值的货币拆成 个,用01背包求解。时间复杂度为 。
这时我们可以考虑每种面值。设 ,对于 以内的任何一个数,我们都可以用 凑出,所以我们并不需要把每种面值的硬币拆成 份,拆成 份即可。
时间复杂度 。
总结
这是一道经典的多重背包优化题目。
对于多重背包来说,数量的个数限制往往可以用二进制的方法组合表示。
如果一道多重背包的题能拆成01背包,那么它必然可以用二进制的方法进行优化,这是一种常见题型。
Code
// Problem: 1601:【例 5】Banknotes
// Contest: SSOIER
// URL: http://ybt.ssoier.cn:8088/problem_show.php?pid=1601
// Memory Limit: 524 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
//#define mo
#define N 210
#define M 200010
int n, m, i, j, k;
int b[N], c[N], v[M], w[M], dp[M];
signed main()
{
// freopen("tiaoshi.in","r",stdin);
// freopen("tiaoshi.out","w",stdout);
memset(dp, 0x3f, sizeof(dp));
n=read(); dp[0]=0;
for(i=1; i<=n; ++i) b[i]=read();
for(i=1; i<=n; ++i) c[i]=read();
for(i=1; i<=n; ++i)
{
k=log2(c[i]);
if(c[i]-k) v[++m]=(c[i]-k)*b[i], w[m]=c[i]-k;
for(j=1; k; k--, j*=2) v[++m]=j*b[i], w[m]=j;
}
n=m; m=read();
for(i=1; i<=n; ++i)
for(j=m; j>=v[i]; --j)
dp[j]=min(dp[j], dp[j-v[i]]+w[i]);
printf("%lld", dp[m]);
return 0;
}
本文来自博客园,作者:zhangtingxi,转载请注明原文链接:https://www.cnblogs.com/zhangtingxi/p/15905471.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战