在一般情况下,硬币值可以是任意的,您提出的问题称为Knapsack Problem,并且已知属于 NP-complete (Pearson, D. 2004),因此无法在多项式时间内解决比如动态规划。
以 x[2] = 51, x[1] = 50, x[0] = 1, X = 100 的病态为例。那么就需要算法“考虑”用硬币找零的可能性x[2],或者从 x[1] 开始进行更改。用于国家造币的第一步,也称为Greedy Algorithm -- to wit,“使用小于工作总量的最大硬币”,不适用于病态造币。相反,此类算法经历了组合爆炸,使它们符合 NP-complete 的条件。
对于某些特殊的硬币价值安排,例如几乎所有实际使用的硬币价值安排,包括虚构系统 X[i+1] == 2 * X[i],有非常快的算法,甚至 O(1)在给定的虚构情况下,确定最佳输出。这些算法利用硬币价值的属性。
我不知道动态编程解决方案:一种利用编程主题所需的最佳子解决方案的解决方案。一般来说,一个问题只能通过动态规划来解决,如果它可以分解为子问题,当优化解决时,可以重新组合成一个可证明是最优的解决方案。也就是说,如果程序员不能在数学上证明(“证明”)重新组合问题的最优子解会产生最优解,则不能应用动态规划。
动态规划的一个常见示例是多个矩阵相乘的应用。根据矩阵的大小,选择将 A·B·C 评估为两种等效形式之一:((A·B)·C) 或 (A·(B· C)) 导致计算不同数量的乘法和加法。也就是说,一种方法比另一种方法更优化(更快)。动态编程是将不同方法的计算成本制成表格的主题,并根据运行时动态计算的时间表(或程序)执行实际计算。
一个关键特性是计算是根据计算出的计划执行的,而不是通过枚举所有可能的组合来执行的——无论枚举是递归执行还是迭代执行。在矩阵相乘的例子中,在每一步,只选择成本最低的乘法。因此,永远不会计算中间成本次优计划的可能成本。换句话说,调度不是通过搜索所有可能的调度以获得最优调度来计算的,而是通过从无到有逐步构建最优调度来计算的。
术语“动态规划”可以与“线性规划”相比较,其中“程序”也用于表示“调度”的意思。
要了解有关动态编程的更多信息,请参阅我所知道的关于算法的最伟大的书籍,"Introduction to Algorithms" by Cormen, Leiserson, Rivest, and Stein.“Rivest”是“RSA”的“R”,而动态编程只是分数的一章。