The Fewest Coins (混合背包)

有的物品只可以取一次或不取(基本的0-1背包),有的物品可以取无限次(完全背包),有的物品可以取的次数有一个上限(多重背包),就是混合背包问题。

The Fewest Coins

题意:

农夫John到城里去买一些农具。John是一个非常有效率的人,他总是以这样一种方式来买他的货物:最少数量的硬币易手,也就是他用来支付的硬币的数量加上他收到的找零的硬币数量要最小化。请您帮助他确定这个最小值是多少。
农夫John想购买T (1≤T≤10,000)美分的商品。货币体系有N (1 ≤ N ≤ 100)种不同的硬币,其面值为V1, V2, …, VN (1 ≤ Vi ≤ 120)。农夫John有面值为V1的硬币 C1枚,面值为 V2的硬币C2枚,…,面价为VN的硬币CN 枚(0 ≤ Ci ≤ 10,000)。店主则拥有所有的硬币无限枚,并且总是以最有效的方式进行找零(尽管农夫John必须确保以能够进行正确的找零方式付款)。

输入

第一行:两个用空格分隔的整数N和T;
第二行:N个用空格分隔的整数,分别为V1, V2, …, VN;
第三行:N个用空格分隔的整数,分别为 C1, C2, …, CN。

输出

输出1行,给出一个整数,在支付和找零中使用硬币的最小数。如果农夫John支付和接收准确的找零是不可能的,输出-1。

题解

首先用完全背包预处理找零j的时候最少需要多少硬币,然后用多重背包处理付款j的时候最少需要多少银币,最后将两个加起来就行,求最小值。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
using namespace std;
const int inf=0x3f3f3f3f;
//约翰对不同金额所付的最少硬币数量 
int dp1[25000];
//店长对不同金额所付的最少硬币数量 
int dp2[25000];
int v[105],w[105];
//完全背包 
void com(int w,int sum)
{
	for(int i=w;i<=sum;i++)
		dp2[i]=min(dp2[i],dp2[i-w]+1);
}
//多重背包 
void mul(int v,int w,int sum)
{
	if(w*v>=sum){
		for(int i=w;i<=sum;i++)
			dp1[i]=min(dp1[i],dp1[i-w]+1);
	}else{
		int k=1;
		while(k<v)
		{
			for(int i=sum;i>=k*w;i--)
				dp1[i]=min(dp1[i],dp1[i-k*w]+k);
			v-=k;
			k*=2;
		}
		for(int i=sum;i>=v*w;i--)
			dp1[i]=min(dp1[i],dp1[i-v*w]+v);
	}
}
int main()
{
	int n,t;
	scanf("%d%d",&n,&t);
	int sum=0;
	for(int i=0;i<n;i++)
	{
		scanf("%d",&w[i]);
		sum=max(sum,w[i]);
	}
	for(int i=0;i<n;i++)
		scanf("%d",&v[i]);
	sum=sum*sum+t+1;
	memset(dp1,inf,sizeof(dp1));
	memset(dp2,inf,sizeof(dp2));
	dp1[0]=0;dp2[0]=0;
	for(int i=0;i<n;i++)
	{
		com(w[i],sum);
		mul(v[i],w[i],sum);
	}
	int res=inf;
	for(int i=t;i<=sum;i++)
		res=min(res,dp1[i]+dp2[i-t]);
	if(res==inf)
		cout<<-1<<endl;
	else
		cout<<res<<endl;
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值