开始动态编程 - 贪婪的硬币改变帮助

时间:2011-10-30 14:46:49

标签: java algorithm dynamic dynamic-programming coin-change

我目前正在编写一本关于算法设计的书,并遇到了一个问题,你必须用动态编程实现一个贪婪的算法来解决硬币变化问题。

我试图实现这一点,我无法弄清楚或理解我书中给出的算法。算法如下(在评论中我的(缺乏)理解):

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];
    }

有人可以向我解释一下我缺少什么,如何解决这个问题,以及该算法应该如何运作?动态编程似乎是一个非常有用的工具,但我无法理解它。我一直在递归地思考。

4 个答案:

答案 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);
}