题意:一个人有n中硬币,其中每种硬币的面值为v[i],每种硬币的个数为c[i],然后卖货的那个人硬币数无限,现在要买T价值的货,问最后交易的硬币数最少能用多少?
题解:使用完全背包打出店主,使用多重背包打出这个人到j钱所用硬币最少的个数,或者做多重背包可以转化成完全背包加限制的做法,两个都能做,但是这个题感觉题意是好的,但是吧,有坑,有人跳坑,有人就不跳,我这个题刚开始不知道范围应该定多大,然后初始化又初始化的有点小,最后还是过了。
附上代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e2+5;
const int maxt=25000;
const int V=20000;
const int inf=0x3f3f3f3f;
int n,t,v[maxn],c[maxn];
int dp1[maxt],dp2[maxt];
void zeroonepack(int v,int k)
{
for(int i=V;i>=v;i--){
dp2[i]=min(dp2[i],dp2[i-v]+k);
}
}
void completepack(int v)
{
for(int i=v;i<=V;i++){
dp2[i]=min(dp2[i],dp2[i-v]+1);
}
}
void multipack(int v,int num)
{
if(v*num>=V){
completepack(v);
return ;
}
for(int k=1;k<=num;k<<=1){
zeroonepack(k*v,k);
num-=k;
}
if(num){
zeroonepack(num*v,num);
}
}
int main()
{
while(scanf("%d%d",&n,&t)!=EOF){
for(int i=1;i<=n;i++){
scanf("%d",&v[i]);
}
for(int i=1;i<=n;i++){
scanf("%d",&c[i]);
}
memset(dp1,inf,sizeof(dp1));
dp1[0]=0;
for(int i=1;i<=n;i++){
for(int j=v[i];j<=V;j++){
dp1[j]=min(dp1[j],dp1[j-v[i]]+1);
}
}
memset(dp2,inf,sizeof(dp2));
dp2[0]=0;
for(int i=1;i<=n;i++){
multipack(v[i],c[i]);
}
int ans=inf;
for(int i=t;i<=V;i++){
ans=min(ans,dp1[i-t]+dp2[i]);
}
if(ans==inf){
printf("-1\n");
}else{
printf("%d\n",ans);
}
}
return 0;
}