POJ 3260 The Fewest Coins(背包问题)

 

【题目链接】 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\n",ans);
    }return 0;
}
posted @ 2017-04-13 16:51  forever97  阅读(130)  评论(0编辑  收藏  举报