zoukankan      html  css  js  c++  java
  • 硬币找零问题算法几种不同的代码实现方式(使用Python实现)

    问题描述

      假设你为一家自动售货机厂家编程序,自动售货机要每次找给顾客最少数量硬币;假设某次顾客投进$1纸币,买了ȼ37的东西,要找ȼ63,那么最少数量就是:2个quarter(ȼ25)、1个dime(ȼ10)和3个penny(ȼ1),一共6个.
      分别使用贪心算法,递归,以及递归的优化版本:递归 + 备忘录技术,与动态规划四种解法

       问题抽象: coin_list = [1,10,25,100]. coin = 63. 在所给定coin_list等于coin最少个数.(63的最优组合是25 25 10 1 1 1.一共6个)




    解法一:贪心算法

    def get_min_coins(money_value):  # 贪心版本
        '''
        贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。
        也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
        '''
        return_list = []
        money_coins = [1,5,10,25,100] # 不兼容爱尔波尼亚的21分硬币.其实63的最优解应该是三个21的硬币.贪心算法的局限性
        money_coins_sorted = sorted(money_coins,reverse=True)
    
        
    
        for current_value in money_coins_sorted:
    
            len_current_value = money_value // current_value 
            return_list += [current_value] * len_current_value
            money_value = money_value - current_value*len_current_value
            '''
            第一次: len_current_value == 2 , return_list = [25,25] , money_value ==  13
            第二次: ...
            第三次: ...
            第四次: ...
    
            '''
            if money_value <=0: # 截至条件
                break
        return return_list
    
    #print(get_min_coins(63))
    
    
    

    解法二:递归求解

    
    
    def recMC(coin_value_list,money_value): # 使用递归求得最优解
    
        '''
        递归三条件:
            不断缩小自身规模
            不断调用自身
            有结束条件
        其中,递归是自顶向下进行计算的.
        '''
        min_len = money_value
        if money_value in coin_value_list: # 递归结束条件
           return 1
        else:
            for current_value in [c for c in coin_value_list if c < money_value]:
                now_len = 1 + recMC(coin_value_list,money_value-current_value) # 调用自身,且缩小规模
                if now_len < min_len:
                    min_len = now_len
    
        return min_len
    
    # print(recMC([1,5,10,25], 63)) # 这个程序执行的太慢了.一共需要执行67,716,925次.
    
    

    解法三:递归优化:备忘录技术

    
    
    def recDc(coin_value_list,money_value,know_results): # 递归改进版本
        '''
        递归改进的关键是消除重复计算.其中有一种技术是备忘录技术.
    
        可以用一个表将计算过的中间结果保存起来,在计算之前查表看看是否已经计算过
    
        在递归调用之前,先查找表中是否已有部分找零的最优解如果有,
        直接返回最优解而不进行递归调用如果没有,才进行递归调用
        '''
        min_len = money_value
        print(know_results)
        if money_value in coin_value_list:
            return 1
        elif know_results[money_value] !=  0:
            return know_results[money_value]
    
        else:
            for i in [c for c in coin_value_list if c < money_value]:
                now_len = 1 + recDc(coin_value_list,money_value-i,know_results)
    
                if now_len < min_len:
                    min_len = now_len
                    know_results[money_value] = now_len
                    print(know_results)
        
        return min_len
    
    # print(recDc([1,5,10,25],63,[0]*64))
    

    解法四:动态规划

    
    
    def dpMakeChange (coinValueList,change,minCoins): # 动态规划解法
        '''
        动态规划:其所求的最优解是由子问题的最优解构成的.
        
        动态规划是自底向上的计算.
    
        在找零递加的过程中,设法保持每一分钱的递加都是最优解,一直加到求解找零钱
        数,自然得到最优解
        '''
        for coin in range(1,change+1):
            
            min_len = coin
    
            for i in [ c for c in coinValueList if c <=coin]:
                if minCoins[coin-i] + 1 < min_len:
                    min_len = minCoins[coin-i]+1
            
            minCoins[coin] = min_len
        return minCoins[change]
        
    
    # print(dpMakeChange([1,5,10,25],63,[0]*64))
    
    

    解法四扩展:动态规划扩展

    
    def dp_make_change(coin_value_list,money_value,minCOins,coins_record):# coins_record记录每一个最优解所添加的硬币.用于返回最优硬币
        '''
    
        '''
        for coin in range(1,money_value+1):
            
            min_len = coin
            new_add_coin =1
    
            for i in [c for c in coin_value_list if c <= coin]:
                
                if minCOins[coin-i] + 1 < min_len:
                    min_len = minCOins[coin-i] + 1
                    new_add_coin = i
            minCOins[coin] = min_len
            coins_record[coin] = new_add_coin
        
        # print(coins_record)
        return minCOins[money_value]
    
    def print_coins(cions_record,how_much_money):
        '''
        在得到最后的解后,减去选择的硬币币值,回溯到表格之前的部分找零,
        就能逐步得到每一步所选择的硬币币值
        '''
        rev_cions = []
        while how_much_money>0:
            how_much_money = how_much_money - cions_record[how_much_money]
            rev_cions.append(cions_record[how_much_money])
        return rev_cions
    
    # some_money = 63
    # cions_record = [0]*64
    # print(dp_make_change([1,5,10,25],some_money,[0]*64,cions_record))
    
    # print(print_coins(cions_record,some_money))
    




    参考

  • 相关阅读:
    就业DAY7_web服务器_tcp三次握手四次挥手,返回浏览器需要的页面http服务器
    就业DAY7_web服务器_http协议
    就业DAY6_web服务器_正则表达式
    就业DAY5_多任务_协程
    就业DAY5_多任务_进程,进程池,队列
    win10安装ubuntu系统,报错WslRegisterDistribution failed with error: 0x8007019e
    解决ubuntu与win10双系统时间不同步
    Linux常用压缩解压命令
    ubuntu添加国内源
    解决Ubuntu“下载额外数据文件失败 ttf-mscorefonts-installer”的问题 (转载)
  • 原文地址:https://www.cnblogs.com/gtscool/p/12553971.html
Copyright © 2011-2022 走看看