📜  通过动态编程了解硬币找零问题

📅  最后修改于: 2021-04-27 20:58:18             🧑  作者: Mango

硬币找零问题被许多人认为是理解称为动态规划的编程范式的必不可少的。两者经常总是配对在一起,因为硬币找零问题包含了动态编程的概念。对于那些不了解动态编程的人来说,它是根据Wikipedia提供的,

换句话说,动态问题是一种编程方法,用于将问题简化为较小的部分。例如,如果仅询问您什么是3 * 89?您可能不知道答案,因为您可能知道2 *2。但是,如果您知道3 * 88(264),那么肯定可以推论3 *89。您所要做的就是在前面的倍数上加3,您将得出267的答案。因此,这是对什么是动态编程的非常简单的解释,也许您现在可以看到如何将其有效地用于解决大型时间复杂性问题。
通过牢记上述对动态编程的定义,我们现在可以继续进行“硬币更改问题” 。以下是硬币找零问题的众多变体之一的示例。给定一个硬币列表,即1美分,5美分和10美分,您能确定给定列表中的硬币组合总数以组成数字N吗?
示例1 :假设您给硬币1分,5分和10分,而N = 8分,那么您可以安排获得8分的硬币的总数是多少。

Input: N=8
        Coins : 1, 5, 10
Output: 2

Explanation: 
1 way: 
      1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 = 8 cents.
2 way:
      1 + 1 + 1 + 5 = 8 cents.

您所要做的就是确定以8美分计价的所有方法。八个1分钱加起来等于8分钱。三1分加一5分便是8分。因此,共有两种方式给出了硬币1、5和10的列表,以获得8美分。
示例2 :假设您给硬币1分,5分和10分,而N = 10分,那么您可以安排获得10分的硬币的总数是多少。

Input : N=10
        Coins : 1, 5, 10
Output : 4
Explanation: 
1 way: 
   1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 = 10 cents.
2 way: 
   1 + 1 + 1 + 1 + 1 + 5 = 10 cents.
3 way: 
   5 + 5 = 10 cents.
4 way: 
   10 cents = 10 cents.

现在我们知道了问题陈述以及如何找到较小值的解决方案,我们如何确定增加较大值的硬币组合的总数?我们写一个程序。我们如何编写程序来计算所有获得较大N值的方法?很简单,我们使用动态编程。请记住,动态编程背后的想法是将问题的每个部分切成小块。与页面顶部的示例相似。如果我们不知道4 * 36的值,但是知道4 * 35的值(140),我们可以将这个值加4并得到4 * 36的答案,顺便说一下是144。
好的,所以我们了解了我们必须做的事情,但是程序将如何确定硬币列表可以输出N种方式呢?好吧,让我们看一下这个例子。

N = 12         
Index of Array: [0, 1,  2]
Array of coins: [1, 5, 10]

这是一堆硬币,分别是1美分,5美分和10美分。 N是12美分。因此,我们需要想出一种可以使用这些硬币价值并确定我们赚取12美分的方法的方法。
动态思考,我们需要弄清楚如何添加到以前的数据。因此,这意味着我们必须添加到以前的解决方案中,而不是对相同的值进行重新计算。显然,我们必须遍历整个硬币阵列。我们还需要一种方法来查看硬币是否大于N值。
一种实现方法是让一个数组一直计数到第N个值
所以 …
多种方法:

[0, 0, 0 ..... Nth value] in our case it would be up to 12.

之所以要使用第N个值的数组,是因为这样,我们就可以确定硬币在方式数组的索引处构成值的方式数量。之所以这样做,是因为如果我们可以确定一个硬币大于该索引处的值,那么显然我们不能使用该硬币来确定硬币的组合,因为该硬币大于该值。通过示例可以更好地理解这一点。
以上述数字为例。

N = 12         
Index of Array of Coins:    
  [0, 1,  2]     
Array of coins:
  [1, 5, 10]

Index of Array of ways:   
  [0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10,  11,  12]
Array of  ways:            
  [0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   0,    0]

在开始迭代之前,我们必须为Ways数组提供一个预定义的值。我们必须将Ways数组的索引0处的第一个元素设置为1。这是因为有1种方法可以使用0个硬币使数字0。
因此,如果我们开始遍历所有coins数组并将这些元素与Ways数组进行比较,我们将确定硬币可以使用多少次来制作Ways数组的索引处的值。
例如…
首先设置方式[0] = 1。
让我们比较一下第一枚硬币,即1美分。

N = 12         
Index of Array of Coins:    
  [0, 1,  2]     
Array of coins:             
  [1, 5, 10]

Index of Array of ways:    
  [0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10,  11,  12]
Array of  ways:            
  [0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,   0,    0]

Then compare coins[0] to all of the index's 
of ways array. If the value of the coin is less 
than or equal to the ways index, then
ways[j-coins[i]]+ways[j] is the new value of 
ways[j]. We do this because we are 
trying to break each part down into smaller 
pieces. You will see what is happening as 
you continue to read. So comparing each value of the 
ways index to the first coin, we get the following.

Index of Array of ways:    
  [0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10,  11,  12]
Array of  ways:            
  [1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,   1,    1]

现在比较第二枚硬币5美分。

N = 12         
Index of Array of Coins:    
  [0, 1,  2]     
Array of coins:             
  [1, 5, 10]

Index of Array of ways:    
  [0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10,  11,  12]
Array of  ways:            
  [1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,   1,    1]

Comparing 5 cents to each of the index and
making that same comparison, if the value 
of the coin is smaller than the value of 
the index at the ways array then ways[j-coins[i]]+ways[j] 
is the new value of ways[j]. Thus we
get the following.

Index of Array of ways:    
  [0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10,  11,  12]
Array of  ways:            
  [1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  3,   3,    3]

We are determining how many times the second
coin goes into all of the values leading up the
Nth coin. Why are we using all 
of the coins? It is to check our previous 
result dynamically and update our answer 
instead of recalculating all over again. 
For example take the element at index 10 
the answer is 3 so far. But how did we get 3? 
We know that the value of 10-5 is 5 so that
is our j-coins[i] value, that is the 
difference of what needs to be made up to 
make the amount 10. So we look at index 5 of the
ways array and see it has the value 2, for
the same reason as above, there are so far 2 
ways to obtain the value 5. So if there are 
2 ways to obtain the value 5 then those ways
plus the current number of ways is the new
updated value of the TOTAL 
ways to get the value at index 10.                                    

现在让我们比较一下第三枚硬币,即10美分。

N = 12         
Index of Array of Coins:    
  [0, 1,  2]     
Array of coins:             
  [1, 5, 10]

Comparing 10 cents to each of the index
and making that same comparison, if the 
value of the coin is smaller than the value of the 
index at the ways array then 
ways[j-coins[i]]+ways[j] is the new value of ways[j]. 
Thus we get the following.


Index of Array of ways:    
  [0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10,  11,  12]
Array of  ways:            
  [1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  4,   4,    4]

So the answer to our example is ways[12] which is 4.

考虑到以上所有内容,让我们看下面的以下程序。

C++
#include 
using namespace std;
 
/* We have input values of N and an array Coins
  that holds all of the coins. We use data type
  of long because we want to be able to test
  large values
without integer overflow*/
long getNumberOfWays(long N, vector Coins)
{
     
    // Create the ways array to 1 plus the amount
    // to stop overflow
    vector ways(N + 1);
 
    // Set the first way to 1 because its 0 and
    // there is 1 way to make 0 with 0 coins
    ways[0] = 1;
 
     // Go through all of the coins
    for(int i = 0; i < Coins.size(); i++)
    {
         
        // Make a comparison to each index value
        // of ways with the coin value.
        for(int j = 0; j < ways.size(); j++)
        {
            if (Coins[i] <= j)
            {
                 
                // Update the ways array
                ways[j] += ways[(j - Coins[i])];
            }
        }
    }
 
    // Return the value at the Nth position
    // of the ways array.
    return ways[N];
}
 
void printArray(vector coins)
{
    for(long i : coins)
        cout << i << "\n";
}
 
// Driver Code
int main()
{
    vector Coins = { 1, 5, 10 };
     
    cout << "The Coins Array:" << endl;
    printArray(Coins);
     
    cout << "Solution:" << endl;
    cout << getNumberOfWays(12, Coins) << endl;
}
 
// This code is contributed by mohit kumar 29


Java
/* We have input values of N and an array Coins 
  that holds all of the coins. We use data type
  of long because we want to be able to test
  large values
without integer overflow*/
 
class getWays {
 
    static long getNumberOfWays(long N, long[] Coins)
    {
        // Create the ways array to 1 plus the amount
        // to stop overflow
        long[] ways = new long[(int)N + 1];
 
        // Set the first way to 1 because its 0 and
        // there is 1 way to make 0 with 0 coins
        ways[0] = 1;
 
         // Go through all of the coins
        for (int i = 0; i < Coins.length; i++) {
 
            // Make a comparison to each index value
            // of ways with the coin value.
            for (int j = 0; j < ways.length; j++) {
                if (Coins[i] <= j) {
      
                    // Update the ways array
                    ways[j] += ways[(int)(j - Coins[i])];
                }
            }
        }
 
        // return the value at the Nth position
        // of the ways array.   
        return ways[(int)N];
    }
 
    static void printArray(long[] coins)
    {
        for (long i : coins)
            System.out.println(i);
    }
 
    public static void main(String args[])
    {
        long Coins[] = { 1, 5, 10 };
 
        System.out.println("The Coins Array:");
        printArray(Coins);
 
        System.out.println("Solution:");
        System.out.println(getNumberOfWays(12, Coins));
    }
}


Python3
''' We have input values of N and an array Coins
that holds all of the coins. We use data type
of because long we want to be able to test
large values
without integer overflow'''
 
def getNumberOfWays(N, Coins):
 
    # Create the ways array to 1 plus the amount
    # to stop overflow
    ways = [0] * (N + 1);
 
    # Set the first way to 1 because its 0 and
    # there is 1 way to make 0 with 0 coins
    ways[0] = 1;
 
    # Go through all of the coins
    for i in range(len(Coins)):
 
        # Make a comparison to each index value
        # of ways with the coin value.
        for j in range(len(ways)):
            if (Coins[i] <= j):
 
                # Update the ways array
                ways[j] += ways[(int)(j - Coins[i])];
 
    # return the value at the Nth position
    # of the ways array.
    return ways[N];
 
def printArray(coins):
    for i in coins:
        print(i);
 
if __name__ == '__main__':
    Coins = [1, 5, 10];
 
    print("The Coins Array:");
    printArray(Coins);
 
    print("Solution:",end="");
    print(getNumberOfWays(12, Coins));
 
# This code is contributed by 29AjayKumar


C#
/* We have input values of N and
an array Coins that holds all of
the coins. We use data type of
long because we want to be able
to test large values without
integer overflow*/
using System;
 
public class getWays
{
 
    static long getNumberOfWays(long N, long[] Coins)
    {
        // Create the ways array to 1 plus the amount
        // to stop overflow
        long[] ways = new long[(int)N + 1];
 
        // Set the first way to 1 because its 0 and
        // there is 1 way to make 0 with 0 coins
        ways[0] = 1;
 
        // Go through all of the coins
        for (int i = 0; i < Coins.Length; i++)
        {
 
            // Make a comparison to each index value
            // of ways with the coin value.
            for (int j = 0; j < ways.Length; j++)
            {
                if (Coins[i] <= j)
                {
     
                    // Update the ways array
                    ways[j] += ways[(int)(j - Coins[i])];
                }
            }
        }
 
        // return the value at the Nth position
        // of the ways array.
        return ways[(int)N];
    }
 
    static void printArray(long[] coins)
    {
        foreach (long i in coins)
            Console.WriteLine(i);
    }
 
    // Driver code
    public static void Main(String []args)
    {
        long []Coins = { 1, 5, 10 };
 
        Console.WriteLine("The Coins Array:");
        printArray(Coins);
 
        Console.WriteLine("Solution:");
        Console.WriteLine(getNumberOfWays(12, Coins));
    }
}
 
// This code has been contributed by 29AjayKumar


输出:
The Coins Array:
1
5
10
Solution:
4