我目前正在编写一本关于算法设计的书,并遇到了一个问题,你必须用动态编程实现一个贪婪的算法来解决硬币变化问题。
我试图实现这一点,我无法弄清楚或理解我书中给出的算法。算法如下(在评论中我的(缺乏)理解):
Change(p) {
C[0] = 0
for(i=1 to p) //cycling from 1 to the value of change we want, p
min = infinity
for(j=1 to k( //cyle from 1 to...?
if dj <=i then
if(1+C[i-dj] < min) then
min = 1+C[i-dj]
endif
endif
endfor
C[i] = min
endfor
return C[p]
}
我尝试解释正在发生的事情:
/**
*
* @param d
* currency divisions
* @param p
* target
* @return number of coins
*/
public static int change(int[] d, int p) {
int[] tempArray = new int[Integer.MAX_VALUE]; // tempArray to store set
// of coins forming
// answer
for (int i = 1; i <= p; i++) { // cycling up to the wanted value
int min = Integer.MAX_VALUE; //assigning current minimum number of coints
for (int value : d) {//cycling through possible values
if (value < i) {
if (1 + tempArray[i - value] < min) { //if current value is less than min
min = 1 + tempArray[1 - value];//assign it
}
}
}
tempArray[i] = min; //assign min value to array of coins
}
System.out.println("help"); // :(
return tempArray[p];
}
有人可以向我解释一下我缺少什么,如何解决这个问题,以及该算法应该如何运作?动态编程似乎是一个非常有用的工具,但我无法理解它。我一直在递归地思考。
答案 0 :(得分:0)
动态编程的本质是将问题分解为子问题,然后开始向上构建解决方案。这个想法是,如果你解决了“n”子问题,你可以将它们结合起来,这种组合将成为整个问题的解决方案。递归是动态编程的一个例子,除了它遇到潜在的堆栈溢出问题。另一种技术称为memoization,它可以缓存结果以加快查找时间,而不是重新计算已经计算的问题。这节省了大量处理并加快了程序的速度。至于贪婪的硬币变化问题,本质上是寻找最大面额并使用它直到它不能再使用(即以最大面额重复划分总量并跟踪剩余部分)然后继续使用下一个最大并重复相同的过程,直到你留下可以用最小面额表示的最低金额。您可以将min值一直存储在数组中,并在找到新的最小值(即memoization)时继续更新它。如果我错了,我希望有人能纠正我。
编辑:然而请注意,并非所有问题都可以通过动态编程解决,动态编程与任何编程语言无关,而只是用于解决优化问题的技术名称。答案 1 :(得分:0)
这似乎是硬件问题,所以我会给出一些指示。首先要做的是,通过DP解决问题是“Think Top Dwon并解决自下而上”。
“自上而下” - 这是您制定递归关系的部分
对于Eg:如果n <1或T(n-1)则T(n)= 0;
递归关系依赖于先前计算的子问题。
“解决自下而上” - 这是您的代码将根据上述递归关系自下而上解决问题的部分。
通常编码很简单,更难的部分是提出一个良好的递归关系(虽然不会有递归)。
答案 2 :(得分:0)
请参阅此wikipedia link
摘录:
贪婪的选择属性我们可以做出最好的选择 然后解决后来出现的子问题。选择 由贪心算法制作可能取决于目前为止所做的选择但不是 未来的选择或子问题的所有解决方案。它 迭代地使一个接一个的贪婪选择,减少每个给定的 问题变成了一个小问题。换句话说,贪婪的算法永远不会 重新考虑其选择。这是与动态的主要区别 编程,这是详尽的,并保证找到 解。在每个阶段之后,动态编程基于决策 关于前一阶段做出的所有决定,并可能会重新考虑 前一阶段解决方案的算法路径。
您的代码遍历int p
获得最佳选择并将其放入数组tempArray
,然后使用此值检查下一次迭代中的最佳选择。
答案 3 :(得分:0)
派对有点晚了,但你的功能已经有效了。
public static int change(int[] d, int p) {
// tempArray to store set of coins forming answer
int[] tempArray = new int[Integer.MAX_VALUE];
tempArray[0] = 0; // INITIAL STEP MISSING
for (int i = 1; i <= p; ++i) { // cycling up to the wanted value
// assigning current minimum number of coins
int min = Integer.MAX_VALUE;
// cycling through possible values
for (int value : d) {
if (value <= i) { // FIX missing = in <=
// if current value is less than min
if (1 + tempArray[i - value] < min) {
// FIX, it's [i-value] not [1-value]
min = 1 + tempArray[i - value];
}
}
}
tempArray[i] = min; // assign min value to array of coins
}
return tempArray[p];
}
使用它。
public static void main(String[] args) {
int[] coins = new int[] { 25, 12, 10, 5, 1 };
int coinCount = change(coins, 15);
System.out.println("min change: " + coinCount);
}