POJ - 3260 The Fewest Coins ( 多重背包 min 价值为1)

本文介绍了如何解决一个与硬币找零有关的数学问题。当支付和找零涉及到多种硬币时,如何使用最少的硬币种类进行交易。问题转化为多重背包与完全背包的组合,通过转换max到min来解决多重背包问题,完全背包部分则直接套用模板。文章提供了详细思路和代码实现。
Farmer John has gone to town to buy some farm supplies. Being a very efficient man, he always pays for his goods in such a way that the smallest number of coins changes hands, i.e., the number of coins he uses to pay plus the number of coins he receives in change is minimized. Help him to determine what this minimum number is.


FJ wants to buy T (1 ≤ T ≤ 10,000) cents of supplies. The currency system has N (1 ≤ N ≤ 100) different coins, with values V1, V2, ..., VN (1 ≤ Vi ≤ 120). Farmer John is carrying C1 coins of value V1, C2 coins of value V2, ...., and CN coins of value VN (0 ≤ Ci ≤ 10,000). The shopkeeper has an unlimited supply of all the coins, and always makes change in the most efficient manner (although Farmer John must be sure to pay in a way that makes it possible to make the correct change).


Input
Line 1: Two space-separated integers: N and T. 
Line 2: N space-separated integers, respectively V 1, V 2, ..., VN coins ( V 1, ... VN) 
Line 3: N space-separated integers, respectively C 1, C 2, ..., CN
Output
Line 1: A line containing a single integer, the minimum number of coins involved in a payment and change-making. If it is impossible for Farmer John to pay and receive exact change, output -1.
Sample Input
3 70
5 25 50
5 2 1
Sample Output
3
Hint

Farmer John pays 75 cents using a 50 cents and a 25 cents coin, and receives a 5 cents coin in change, for a total of 3 coins used in the transaction.

题意:给出硬币的种类,物品的价格,商店有那些种类的硬币无数个,而你拥有有限个硬币,在支付和找钱的过程中一共最少需要多少种硬币。

思路:题目分为支付和找钱,可以看出支付的时候为多重背包,找钱的时候为完全背包

多重背包,但是背包是求最少有多少种,这就和平时的背包不一样了,平时的背包是最多,那么在max的位置转换成min就可以了,此题目的背包重量:maxw*maxw+m(求解方法:https://www.cnblogs.com/ACMan/archive/2012/08/14/2637437.html,也可以把数组开大即可),硬币的面值为重量,价值为1,因为此题目是求种类,所以每种硬币的价值都是一样的都是1
完全背包:套模板即可

2个背包开2个数组,在计算硬币种类详情看代码

#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
typedef long long ll;
#define INF 1<<29
int m,n,maxn;
int w[105],c[105];
int dp[25000];//dp[]买家的硬币种类
int f[25000]; //f[]售货员的硬币种类
void ZeroOnePack(int w,int v)
{
    for(int i=maxn;i>=w;i--)
        dp[i]=min(dp[i],dp[i-w]+v);
        // printf("01   %d\n",dp[maxn]);
}
void  CompletePack(int w,int v)
{
    for(int i=w;i<=maxn;i++)
        dp[i]=min(dp[i],dp[i-w]+v);
      //  printf("con   %d\n",dp[maxn]);
}
void  MultiplePack(int w,int v,int cnt)
{
    //printf("%d %d %d %d \n",w,v,cnt,maxn);
    if(cnt*w>=maxn) //物品无限的完全背包
    {
        CompletePack(w,v);
        return ;
    }
    else{
    int k=1; //否则进行0-1背包转化
    while(k<cnt){
        ZeroOnePack(k*w,k*v);
        cnt-=k;
        k=k*2;
    }
    ZeroOnePack(cnt*w,cnt*v);
    return ;
    }
}//完全背包模板
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        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;     //得到maxnn
        fill(dp,dp+maxn+1,INF); //把dp[0]~dp[maxn]赋值INF
        fill(f,f+maxn+1,INF);
        dp[0]=0; f[0]=0;
        for(int i=1;i<=n;i++)
            MultiplePack(w[i],1,c[i]);

        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; //不能找出,调整输出为-1.
        printf("%d\n",ans);
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值