最少硬币问题

给定一些硬币,求给定金额下,最少硬币的组合。


可以看出是背包问题




#include <iostream>
#include <limits>

using namespace std;

int main()
{

	int money[7] = {2,1,5,10,20,50,100};
	int cash;
	int dp[100000];
	int num[100000];
	//memset(dp,0,sizeof(dp));
	dp[0] = 0;
	for (int i=1;i<100000;++i)
		dp[i] = numeric_limits<int>::min();
	memset(num,0,sizeof(num));
	while (scanf("%d",&cash)!=EOF)
	{
		for (int i=0;i<7;++i)
		{
			for (int v=money[i];v<=cash;++v)
			{
				
				if(v ==dp[v-money[i]] +money[i])//保证dp[v],当金额为v时,各种组合的和也是v
				{
					dp[v] = dp[v-money[i]] +money[i];
					if(!num[v])
						num[v] = num[v-money[i]] + 1;
					else
						num[v] = min(num[v],num[v-money[i]] + 1);
				}
			}
		}
		cout<<num[cash]<<endl;
			
	}
	return 0;
}

上面的代码我自己都看不懂了。。。

下面的代码可以看出与背包问题的关联,其中每个硬币的权重为1,求最少硬币的数量也就是求权重之和最小的,其中面值可以看成是体积。但是要求的是必须完全等于给定的面值,如果组合成的值小于面值,则f[n] = max

void multiPacket(int cost,int a[],int Volume,int weight,int backtrace[]) {
    for (int v = cost; v <=Volume; ++v) {
        if (a[v-cost] == numeric_limits<int>::max())
            continue;
        if(a[v-cost] + weight < a[v]) {
            a[v] = a[v-cost] +weight;
            backtrace[v] = cost;
        }
       //a[v] = min(a[v],a[v-cost] + weight);
    }
}

void print(int backtrace[], int acount ) {
    if (acount > 0) {
        cout<<backtrace[acount]<<" ";
        int rest = acount - backtrace[acount];
        if (rest > 0) {
            print(backtrace,rest);
        }
    }
}

void minChange(int coin[],int n, int acount) {
    int a[1000];
    int backtrace[1000];//backtrace[n],在总数为n时,选择的最后一个零钱的面额
    a[0] = 0;
    for (int i=1; i < 1000;++i) a[i] = numeric_limits<int>::max();
    for (int i = 0; i < n ;++i)
        multiPacket(coin[i],a,acount,1,backtrace);

    cout<<"minNum: "<<a[acount]<<" coins: ";
    print(backtrace,acount);
}

int main() {

    int money [] = {25, 21, 10, 5, 1};
    minChange(money,5,34);
}


在有些情况下是可以用贪心算法计算的,当零钱的种类符合特定的情况,并且零钱充裕


public static int[] MakeChange(int money, int[] changes)
{
    int[] result = new int[changes.Length];

    for (int i = 0; i < changes.Length; i++)
    {
        result[i] = money / changes[i];
        money = money % changes[i];

        if (money == 0) { break; }
    }

    return result;
}


这是一题比较复杂的题目:http://www.nowamagic.net/algorithm/algorithm_CoinsGiveChange.php

设有6 种不同面值的硬币,各硬币的面值分别为5 分,1 角,2 角,5 角,1 元,2元。现要用这些面值的硬币来购物和找钱。购物时可以使用的各种面值的硬币个数存于数组Coins[1:6]中,商店里各面值的硬币有足够多。在1次购物中希望使用最少硬币个数。例如,1 次购物需要付款0.55 元,没有5 角的硬币,只好用2*20+10+5 共4 枚硬币来付款。如果付出1 元,找回4 角5 分,同样需要4 枚硬币。但是如果付出1.05 元(1 枚1元和1 枚5分),找回5 角,只需要3 枚硬币。这个方案用的硬币个数最少。

对于给定的各种面值的硬币个数和付款金额,计算使用硬币个数最少的交易方案。


意思是让客户给出的硬币数量+商店找钱用的硬盘数量  的值最少

change[i]表示商店支付面值为i需要的最少硬币个数;

dp[i]表示顾客现有的硬币数支付面值为i需要的最少硬币数;

w为当前要支付的实际面值,若顾客支付面值为k的钱(k>=w),商家找钱k-w,该条件下最少需要的硬币数为dp[k]+change[k-w],由此推得,最少硬币数为所有符合条件k>=w下最小的dp[k]+change[k-w];

即: ans = min(dp[k]+change[k-w])(k>=w)。

对于change[i],商店里各面值的硬币有足够多,故可用完全背包实现。

对于dp[i],可用混合背包计算


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值