Comprender el problema del cambio de moneda con la programación dinámica

Muchos consideran que el Problema del Cambio de Moneda es esencial para comprender el paradigma de programación conocido como Programación Dinámica . Los dos a menudo siempre están emparejados porque el problema del cambio de moneda abarca los conceptos de programación dinámica. Para los que no saben de programación dinámica es según Wikipedia, 

“tanto un método de optimización matemática como un método de programación de computadoras… se refiere a simplificar un problema complicado dividiéndolo en subproblemas más simples”.

En otras palabras, el problema dinámico es un método de programación que se utiliza para simplificar un problema en partes más pequeñas. Por ejemplo, si te preguntaran simplemente ¿cuánto es 3 * 89? quizás no sepas la respuesta de tu cabeza ya que probablemente sepas lo que es 2 * 2. Sin embargo, si supieras lo que es 3 * 88 (264), entonces ciertamente puedes deducir 3 * 89. Todo lo que tendrías que hacer es agregue 3 al múltiplo anterior y obtendrá la respuesta de 267. Por lo tanto, esa es una explicación muy simple de lo que es la programación dinámica y tal vez ahora pueda ver cómo se puede usar para resolver problemas de gran complejidad de tiempo de manera efectiva.
Teniendo en cuenta la definición anterior de programación dinámica, ahora podemos pasar al problema del cambio de monedas.. El siguiente es un ejemplo de una de las muchas variaciones del problema del cambio de moneda. Dada una lista de monedas, es decir , 1 centavo, 5 centavos y 10 centavos , ¿puedes determinar el número total de combinaciones de las monedas en la lista dada para formar el número N ?
Ejemplo 1 : Suponga que le dan las monedas de 1 centavo, 5 centavos y 10 centavos con N = 8 centavos, ¿cuál es el número total de combinaciones de las monedas que puede organizar para obtener 8 centavos? 

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.

Todo lo que estás haciendo es determinar todas las formas en que puedes llegar a la denominación de 8 centavos. Ocho 1 centavos sumados es igual a 8 centavos. Tres 1 centavo más Uno 5 centavos sumados son 8 centavos. Entonces hay un total de 2 formas dada la lista de monedas 1, 5 y 10 para obtener 8 centavos.
Ejemplo 2 : Suponga que le dan las monedas de 1 centavo, 5 centavos y 10 centavos con N = 10 centavos, ¿cuál es el número total de combinaciones de las monedas que puede organizar para obtener 10 centavos? 

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.

Ahora que conocemos el enunciado del problema y cómo encontrar la solución para valores más pequeños, ¿cómo determinaríamos el número total de combinaciones de monedas que suman valores más grandes ? Escribimos un programa. ¿Cómo escribimos el programa para calcular todas las formas de obtener valores más grandes de N? simple usamos programación dinámica . Recuerde que la idea detrás de la programación dinámica es cortar cada parte del problema en partes más pequeñas. Similar al ejemplo en la parte superior de la página. Si no conocemos el valor de 4 * 36 pero conocemos el valor de 4 * 35 (140), podemos sumar 4 a ese valor y obtener nuestra respuesta de 4 * 36 que, por cierto, es 144. 
Bien, entendemos lo que tenemos que hacer, pero ¿cómo va a determinar un programa de cuántas maneras la lista de monedas puede generar N? Bueno, veamos que este ejemplo. 

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

Esta es una array de monedas, 1 centavo, 5 centavos y 10 centavos. La N es de 12 centavos. Por lo tanto, debemos idear un método que pueda usar esos valores de monedas y determinar la cantidad de formas en que podemos hacer 12 centavos. 
Pensando dinámicamente, necesitamos descubrir cómo agregar a los datos anteriores. Entonces, lo que eso significa es que tenemos que agregar a las soluciones anteriores en lugar de volver a calcular sobre los mismos valores. Claramente, tenemos que iterar a través de toda la array de monedas. También necesitamos una forma de ver si una moneda es más grande que el valor N. 
Una forma de hacer esto es tener una array que cuente hasta el valor N-ésimo
Así que…
variedad de formas: 

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

La razón para tener una array hasta el valor N-ésimo es que podemos determinar el número de formas en que las monedas componen los valores en el índice de la array de formas . Hacemos esto porque si podemos determinar que una moneda es más grande que ese valor en el índice, entonces claramente no podemos usar esa moneda para determinar las combinaciones de las monedas porque esa moneda es más grande que ese valor. Esto se puede entender mejor con un ejemplo.
Usando los números anteriores como ejemplo.

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]

Antes de comenzar a iterar, debemos dar un valor predefinido a nuestra array de formas. Debemos establecer el primer elemento en el índice 0 de la array de formas en 1. Esto se debe a que hay 1 forma de hacer el número 0, usando 0 monedas. 
Entonces, si comenzamos a iterar a través de toda la array de monedas y comparamos los elementos con la array de formas, determinaremos cuántas veces se puede usar una moneda para hacer los valores en el índice de la array de formas.
Por ejemplo…
Primero establece formas[0] = 1.
Comparemos la primera moneda, 1 centavo. 

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]

Comparemos ahora la segunda moneda, 5 centavos.

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.                                    

Comparemos ahora la tercera moneda, 10 centavos. 

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.

Con todo lo anterior en mente, echemos un vistazo al siguiente programa a continuación. 

C++

#include <bits/stdc++.h>
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<long> Coins)
{
     
    // Create the ways array to 1 plus the amount
    // to stop overflow
    vector<long> 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<long> coins)
{
    for(long i : coins)
        cout << i << "\n";
}
 
// Driver Code
int main()
{
    vector<long> 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

Javascript

<script>
/* 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*/
 
function getNumberOfWays(N,Coins)
{
    // Create the ways array to 1 plus the amount
        // to stop overflow
        let ways = new Array(N + 1);
         for(let i=0;i<N+1;i++)
        {
            ways[i]=0;
        }
        // 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 (let i = 0; i < Coins.length; i++) {
  
            // Make a comparison to each index value
            // of ways with the coin value.
            for (let j = 0; j < ways.length; 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];
}
 
function printArray(coins)
{
    for(let i=0;i<coins.length;i++)
    {
        document.write(coins[i]+"<br>");
    }
}
 
let Coins=[1, 5, 10];
document.write("The Coins Array:<br>");
printArray(Coins);
 
document.write("Solution:<br>");
document.write(getNumberOfWays(12, Coins)+"<br>");
 
 
// This code is contributed by patel2127
</script>
Producción: 

The Coins Array:
1
5
10
Solution:
4

Publicación traducida automáticamente

Artículo escrito por Mohammad_Sarker y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *