程序员的算法趣题--入门篇(Q5)(c++描述)

目录

 

题目描述:

思路:

代码实现:


题目描述:

        当下,坐公交或者地铁时大部分人都是刷卡的。不过,时至今日还 在用现金支付的人还是比想象的多。本题我们以安置在公交上的零钱兑 换机为背景。 这个机器可以用纸币兑换到10 日元、50 日元、100 日元和500 日 元硬币的组合,且每种硬币的数量都足够多(因为公交接受的最小额度 为 10 日元,所以不提供 1 日元和 5 日元的硬币)。兑换时,允许机器兑换出本次支付时用不到的硬币。此外,因为在 乘坐公交时,如果兑换出了大量的零钱会比较不便,所以只允许机器最 多兑换出15 枚硬币。譬如用1000 日元纸币兑换时,就不能兑换出 “100 枚 10 日元硬币”的组合。求兑换1000日元纸币时会出现多少种组合?注意,不计硬币兑出的先后顺序思路。

思路:

        书上的思路属于暴力穷举法,个人觉得答案应该有更优的方法。首先我们应该把思路从组合转化为分解上来,即给我1000日元我能怎么分成500、100、50、10。先来分析数字特征: 

我们使用一个int类型数组存储组合情况:

int num_coins[4] = {2, 0, 0, 0};//两枚500的硬币,没有其他面值硬币

既然是分解,当然是从面值最大的情况开始分解,分解后的硬币可继续分解,自然我们需要使用递归函数。为了保证我们分解出来的组合情况不能有重复,怎样递归就显得十分重要(PS:之前写的递归就重复了很多情况,算法学得不精,递归写得头皮发麻)。 我们从最大面值硬币开始分解,而且分解要依次进行,这很关键,举个栗子:(框图中为num_coins数组)

第一个流程图展示的分解就是依次进行,即每一级上面分解的硬币面额是一致的,而且需要尽可能分解,而第二个流程图所展示的分解则会导致分解结果出现重复!

代码实现:

#include <iostream>
#include <string>
using std::string;
/*process one bit can avoid repeated result effectively*/
void splitCoins(const int* num_coins, int amount, int index);
int main() {
    int num_coins[4] = {2, 0, 0, 0};
    splitCoins(num_coins, 2, 0);
    return 0;
}
void splitCoins(const int* num_coins, int amount, int index){//if array is a parameter, then it must be protected by const.
    if (amount > 15)
        return;
    std::cout << num_coins[0] << " " << num_coins[1] << " " << num_coins[2] << " "
              << num_coins[3] << std::endl;
    if ((amount == 15) || index == 3)//如果已经有15枚硬币就不必再分解了
        return;
    int num_coins_index = num_coins[index];//分解级别上的硬币数量
    while (num_coins_index != 0){
        int temp[4] = {num_coins[0], num_coins[1], num_coins[2], num_coins[3]};
        temp[index] = --num_coins_index;
        if (index != 1){
            temp[index + 1] += 5*(num_coins[index] - num_coins_index);
            splitCoins(temp, amount + 4*(num_coins[index] - num_coins_index), index + 1);
        }
        else{
            temp[index + 1] += 2*(num_coins[index] - num_coins_index);
            splitCoins(temp, amount + 1*(num_coins[index] - num_coins_index), index + 1);
        }
    }
}

递归函数中的amount是总硬币数量、index为分解级别(上述流程图中的第几列)   

传递num_coins需要创建临时变量进行深拷贝,不能改变传入的形参。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值