【问题标题】:Change money with python dynamic programming用python动态编程换钱
【发布时间】:2018-04-13 07:18:14
【问题描述】:

这里有两个解决零钱问题的程序。第一个只是一个获得所有组合的递归程序,第二个是使用动态编程。但是,当我在做第二个时,我遇到了麻烦。它应该比第一个更快,但我的程序永远运行来做到这一点。我很确定我使用的是动态编程,但我不知道它有什么问题?

注意:Total 是要改变的钱,units 是一个具有不同值的列表,stored 是一个字典,用来存储一个步骤的值。

第一:

def changeMoney(total, units):
    if ( total == 0 ): 
        return [{}]
    elif ( total < 0 ):
        return []
    else:
        n = len(units)
        ret = []
        for i in range(0,n):
            sols = changeMoney(total-units[i],units[i:n])
            for sol in sols:
                if ( units[i] in sol ):
                    sol[units[i]] += 1
                else:
                    sol[units[i]] = 1
            ret.append(sol)
        return ret
print(dpChangeMoney(300,[100,50,20,10,5,2,1],{}))

第二:

import copy
def dpChangeMoney(total, units, stored):
    key = ".".join(map(str,[total] + units))
    if key in stored:
        return stored[key]
    else:
        if ( total == 0 ):
            return [{}]
        elif ( total < 0 ):
            return []
        else:
            n = len(units)
            for i in range(0,n):
                sols = copy.deepcopy(dpChangeMoney(total-
units[i],units[i:n], stored))
                for sol in sols:
                    if ( units[i] in sol ):
                        sol[units[i]] += 1
                    else:
                        sol[units[i]] = 1
                    if key in stored:
                        if sol not in stored[key]:
                            stored[key] += [sol]
                    else:
                        stored[key] = [sol]
        return stored[key]
print(dpChangeMoney(300,[100,50,20,10,5,2,1],{}))

【问题讨论】:

  • 单位中的数字假定为整数并按降序排列。
  • 你应该只使用一个元组作为 dict 键,而不是构造一个字符串。
  • @TomKarzes 但我猜这不费时间?
  • 正确,它的效率有点低,并且不必要地使代码复杂化,但它不会导致您的问题。
  • dp中的核心点是状态转移方程。在货币兑换中是d[s]=min{d[s-v[i]]+1, d[s]} 。你需要一个例子吗?

标签: python dynamic-programming


【解决方案1】:

这是一种更快的方法:

def dpChangeMoney(total, units, stored, min_ix=0):
    if total < 0:
        return []

    if total == 0:
        return [{}]

    if min_ix == len(units):
        return []

    key = (total, min_ix)
    if key in stored:
        return stored[key]

    sol_list = []
    u = units[min_ix]
    for c in range(total // u + 1):
        sols = dpChangeMoney(total - c*u, units, stored, min_ix + 1)
        for sol in sols:
            if c > 0:
                sol2 = sol.copy()
                sol2[u] = c
            else:
                sol2 = sol
            sol_list.append(sol2)

    stored[key] = sol_list
    return sol_list

如果按如下方式调用,它会打印指定案例的解决方案数:

print(len(dpChangeMoney(300, [100,50,20,10,5,2,1], {})))

结果是:

466800

在我的系统上,这需要不到一秒钟的时间来运行。 (当然,您可以打印实际的解决方案,但有很多!)

查看实际解决方案一共10

print(dpChangeMoney(10, [100,50,20,10,5,2,1], {}))

结果是:

[{1: 10}, {1: 8, 2: 1}, {1: 6, 2: 2}, {1: 4, 2: 3}, {1: 2, 2: 4}, {2: 5}, {1: 5, 5: 1}, {1: 3, 2: 1, 5: 1}, {1: 1, 2: 2, 5: 1}, {5: 2}, {10: 1}]

【讨论】:

  • 太酷了!!!!!!!过段时间我会试试的,但肯定的是,这个算法如果能在一秒钟内运行,它将是一个大师级的程序!!!!
  • 如果你研究它,我想你会弄明白的。我简化了哈希键并消除了继续复制units 切片的需要,但我认为最大的速度改进之一是在添加新解决方案时消除了列表搜索(这真的很慢) .相反,我以不能有任何重复的方式生成解决方案,因此我可以跳过检查。
【解决方案2】:

我只是弄清楚我的算法有什么问题。我将在截止日期后更新一个更快的算法。感谢您的建议和指导。 E

【讨论】:

    猜你喜欢
    • 2020-09-13
    • 2013-12-09
    • 2022-06-15
    • 2020-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-24
    相关资源
    最近更新 更多