【题目链接】 http://poj.org/problem?id=3260
【题目大意】
给出你拥有的货币种类和每种的数量,商店拥有的货币数量是无限的,
问你买一个价值为m的物品,最少的货币流通数量为多少
【题解】
我们可以计算出买不同价值的物品,在没有找钱情况下的最少用币数量,
记为dp[i],这个可以用多重背包来完成,对于商店来说,我们可以计算出,
对于不同额度的找零,最少用币数量,记为f[i],
我们发现,对于货币流通最少,就是求dp[i+m]+f[i]的最小值,
由鸽巢原理可得我们只要计算maxw*maxw+m的dp值就可以了。
【代码】
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int m,n,w[110],c[110],dp[24563],f[24563];
int main(){
while(~scanf("%d%d",&n,&m)){
int maxn=0;
for(int i=1;i<=n;i++)scanf("%d",&w[i]),maxn=max(maxn,w[i]);
for(int i=1;i<=n;i++)scanf("%d",&c[i]);
maxn=maxn*maxn+m+1;
memset(dp,INF,sizeof(dp));
dp[0]=0;
for(int i=1;i<=n;i++){
if(c[i]*w[i]>=maxn){
for(int j=w[i];j<=maxn;j++)dp[j]=min(dp[j],dp[j-w[i]]+1);
}else{
for(int k=1;k<c[i];k<<=1){
for(int j=maxn;j>=w[i]*k;j--)dp[j]=min(dp[j],dp[j-w[i]*k]+k);
c[i]-=k;
}for(int j=maxn;j>=w[i]*c[i];j--)dp[j]=min(dp[j],dp[j-w[i]*c[i]]+c[i]);
}memset(f,INF,sizeof(f));f[0]=0;
}
for(int i=1;i<=n;i++){
for(int j=w[i];j<=maxn;j++)f[j]=min(f[j],f[j-w[i]]+1);
}int ans=INF;
for(int i=0;i<=maxn-m;i++)ans=min(ans,dp[i+m]+f[i]);
if(ans==INF)ans=-1;
printf("%d
",ans);
}return 0;
}