本文概述
给定一个值N, 如果我们要N分钱找零, 并且我们有无限数量的S = {S1, S2, .., Sm}硬币的供应, 我们可以用几种方法进行找零?硬币的顺序无关紧要。
例如, 对于N = 4和S = {1, 2, 3}, 有四个解:{1, 1, 1, 1}, {1, 1, 2}, {2, 2}, {1, 3}。因此输出应为4。对于N = 10且S = {2, 5, 3, 6}, 有五个解:{2, 2, 2, 2, 2}, {2, 2, 3, 3} {2, 2, 6}, {2, 3, 5}和{5, 5}。因此输出应为5。
1)最佳子结构
要计算解决方案的总数, 我们可以将所有解决方案分为两组。
1)不包含第m个硬币(或Sm)的解决方案。
2)包含至少1 Sm的溶液。
设count(S [], m, n)为计算解数的函数, 则可以写为count(S [], m-1, n)和count(S [], m, n-Sm)。
因此, 该问题具有最佳的子结构属性, 因为可以使用子问题的解决方案来解决该问题。
2)重叠子问题
以下是硬币更改问题的简单递归实现。该实现仅遵循上述递归结构。
C++
//Recursive C program for
//coin change problem.
#include<stdio.h>
//Returns the count of ways we can
//sum S[0...m-1] coins to get sum n
int count( int S[], int m, int n )
{
//If n is 0 then there is 1 solution
//(do not include any coin)
if (n == 0)
return 1;
//If n is less than 0 then no
//solution exists
if (n <0)
return 0;
//If there are no coins and n
//is greater than 0, then no
//solution exist
if (m <=0 && n>= 1)
return 0;
//count is sum of solutions (i)
//including S[m-1] (ii) excluding S[m-1]
return count( S, m - 1, n ) + count( S, m, n-S[m-1] );
}
//Driver program to test above function
int main()
{
int i, j;
int arr[] = {1, 2, 3};
int m = sizeof (arr)/sizeof (arr[0]);
printf ( "%d " , count(arr, m, 4));
getchar ();
return 0;
}
Java
//Recursive java program for
//coin change problem.
import java.io.*;
class GFG {
//Returns the count of ways we can
//sum S[0...m-1] coins to get sum n
static int count( int S[], int m, int n )
{
//If n is 0 then there is 1 solution
//(do not include any coin)
if (n == 0 )
return 1 ;
//If n is less than 0 then no
//solution exists
if (n <0 )
return 0 ;
//If there are no coins and n
//is greater than 0, then no
//solution exist
if (m <= 0 && n>= 1 )
return 0 ;
//count is sum of solutions (i)
//including S[m-1] (ii) excluding S[m-1]
return count( S, m - 1 , n ) +
count( S, m, n-S[m- 1 ] );
}
//Driver program to test above function
public static void main(String[] args)
{
int arr[] = { 1 , 2 , 3 };
int m = arr.length;
System.out.println( count(arr, m, 4 ));
}
}
//This article is contributed by vt_m.
Python3
# Recursive Python3 program for
# coin change problem.
# Returns the count of ways we can sum
# S[0...m-1] coins to get sum n
def count(S, m, n ):
# If n is 0 then there is 1
# solution (do not include any coin)
if (n = = 0 ):
return 1
# If n is less than 0 then no
# solution exists
if (n <0 ):
return 0 ;
# If there are no coins and n
# is greater than 0, then no
# solution exist
if (m <= 0 and n> = 1 ):
return 0
# count is sum of solutions (i)
# including S[m-1] (ii) excluding S[m-1]
return count( S, m - 1 , n ) + count( S, m, n - S[m - 1 ] );
# Driver program to test above function
arr = [ 1 , 2 , 3 ]
m = len (arr)
print (count(arr, m, 4 ))
# This code is contributed by Smitha Dinesh Semwal
C#
//Recursive C# program for
//coin change problem.
using System;
class GFG
{
//Returns the count of ways we can
//sum S[0...m-1] coins to get sum n
static int count( int []S, int m, int n )
{
//If n is 0 then there is 1 solution
//(do not include any coin)
if (n == 0)
return 1;
//If n is less than 0 then no
//solution exists
if (n <0)
return 0;
//If there are no coins and n
//is greater than 0, then no
//solution exist
if (m <=0 && n>= 1)
return 0;
//count is sum of solutions (i)
//including S[m-1] (ii) excluding S[m-1]
return count( S, m - 1, n ) +
count( S, m, n - S[m - 1] );
}
//Driver program
public static void Main()
{
int []arr = {1, 2, 3};
int m = arr.Length;
Console.Write( count(arr, m, 4));
}
}
//This code is contributed by Sam007
PHP
<?php
//Recursive PHP program for
//coin change problem.
//Returns the count of ways we can
//sum S[0...m-1] coins to get sum n
function coun( $S , $m , $n )
{
//If n is 0 then there is
//1 solution (do not include
//any coin)
if ( $n == 0)
return 1;
//If n is less than 0 then no
//solution exists
if ( $n <0)
return 0;
//If there are no coins and n
//is greater than 0, then no
//solution exist
if ( $m <= 0 && $n>= 1)
return 0;
//count is sum of solutions (i)
//including S[m-1] (ii) excluding S[m-1]
return coun( $S , $m - 1, $n ) +
coun( $S , $m , $n - $S [ $m - 1] );
}
//Driver Code
$arr = array (1, 2, 3);
$m = count ( $arr );
echo coun( $arr , $m , 4);
//This code is contributed by Sam007
?>
输出:
4
应该注意的是, 上述函数一次又一次地计算相同的子问题。请参见以下递归树, 其中S = {1, 2, 3}, n = 5。
函数C({1}, 3)被调用两次。如果我们绘制完整的树, 则可以看到有许多子问题被多次调用。
C() --> count()
C({1, 2, 3}, 5)
/ \
/ \
C({1, 2, 3}, 2) C({1, 2}, 5)
/ \ / \
/ \ / \
C({1, 2, 3}, -1) C({1, 2}, 2) C({1, 2}, 3) C({1}, 5)
/\ / \ / \
/ \ / \ / \
C({1, 2}, 0) C({1}, 2) C({1, 2}, 1) C({1}, 3) C({1}, 4) C({}, 5)
/\ /\ /\ / \
/\ /\ /\ / \
. . . . . . C({1}, 3) C({}, 4)
/\
/\
. .
由于再次调用了相同的问题, 因此此问题具有"重叠子问题"属性。因此, 硬币更改问题具有两个属性(请参见这个和这个)的动态编程问题。像其他典型的动态编程(DP)问题, 可以通过自下而上的方式构造一个临时数组table [] []来避免相同子问题的重新计算。
动态编程解决方案
C++
//C++ program for coin change problem.
#include<bits/stdc++.h>
using namespace std;
int count( int S[], int m, int n )
{
int i, j, x, y;
//We need n+1 rows as the table
//is constructed in bottom up
//manner using the base case 0
//value case (n = 0)
int table[n + 1][m];
//Fill the enteries for 0
//value case (n = 0)
for (i = 0; i <m; i++)
table[0][i] = 1;
//Fill rest of the table entries
//in bottom up manner
for (i = 1; i <n + 1; i++)
{
for (j = 0; j <m; j++)
{
//Count of solutions including S[j]
x = (i-S[j]>= 0) ? table[i - S[j]][j] : 0;
//Count of solutions excluding S[j]
y = (j>= 1) ? table[i][j - 1] : 0;
//total count
table[i][j] = x + y;
}
}
return table[n][m - 1];
}
//Driver Code
int main()
{
int arr[] = {1, 2, 3};
int m = sizeof (arr)/sizeof (arr[0]);
int n = 4;
cout <<count(arr, m, n);
return 0;
}
//This code is contributed
//by Akanksha Rai(Abby_akku)
C
//C program for coin change problem.
#include<stdio.h>
int count( int S[], int m, int n )
{
int i, j, x, y;
//We need n+1 rows as the table is constructed
//in bottom up manner using the base case 0
//value case (n = 0)
int table[n+1][m];
//Fill the enteries for 0 value case (n = 0)
for (i=0; i<m; i++)
table[0][i] = 1;
//Fill rest of the table entries in bottom
//up manner
for (i = 1; i <n+1; i++)
{
for (j = 0; j <m; j++)
{
//Count of solutions including S[j]
x = (i-S[j]>= 0)? table[i - S[j]][j]: 0;
//Count of solutions excluding S[j]
y = (j>= 1)? table[i][j-1]: 0;
//total count
table[i][j] = x + y;
}
}
return table[n][m-1];
}
//Driver program to test above function
int main()
{
int arr[] = {1, 2, 3};
int m = sizeof (arr)/sizeof (arr[0]);
int n = 4;
printf ( " %d " , count(arr, m, n));
return 0;
}
Java
/* Dynamic Programming Java implementation of Coin
Change problem */
import java.util.Arrays;
class CoinChange
{
static long countWays( int S[], int m, int n)
{
//Time complexity of this function: O(mn)
//Space Complexity of this function: O(n)
//table[i] will be storing the number of solutions
//for value i. We need n+1 rows as the table is
//constructed in bottom up manner using the base
//case (n = 0)
long [] table = new long [n+ 1 ];
//Initialize all table values as 0
Arrays.fill(table, 0 ); //O(n)
//Base case (If given value is 0)
table[ 0 ] = 1 ;
//Pick all coins one by one and update the table[]
//values after the index greater than or equal to
//the value of the picked coin
for ( int i= 0 ; i<m; i++)
for ( int j=S[i]; j<=n; j++)
table[j] += table[j-S[i]];
return table[n];
}
//Driver Function to test above function
public static void main(String args[])
{
int arr[] = { 1 , 2 , 3 };
int m = arr.length;
int n = 4 ;
System.out.println(countWays(arr, m, n));
}
}
//This code is contributed by Pankaj Kumar
python
# Dynamic Programming Python implementation of Coin
# Change problem
def count(S, m, n):
# We need n+1 rows as the table is constructed
# in bottom up manner using the base case 0 value
# case (n = 0)
table = [[ 0 for x in range (m)] for x in range (n + 1 )]
# Fill the entries for 0 value case (n = 0)
for i in range (m):
table[ 0 ][i] = 1
# Fill rest of the table entries in bottom up manner
for i in range ( 1 , n + 1 ):
for j in range (m):
# Count of solutions including S[j]
x = table[i - S[j]][j] if i - S[j]> = 0 else 0
# Count of solutions excluding S[j]
y = table[i][j - 1 ] if j> = 1 else 0
# total count
table[i][j] = x + y
return table[n][m - 1 ]
# Driver program to test above function
arr = [ 1 , 2 , 3 ]
m = len (arr)
n = 4
print (count(arr, m, n))
# This code is contributed by Bhavya Jain
C#
/* Dynamic Programming C# implementation of Coin
Change problem */
using System;
class GFG
{
static long countWays( int []S, int m, int n)
{
//Time complexity of this function: O(mn)
//Space Complexity of this function: O(n)
//table[i] will be storing the number of solutions
//for value i. We need n+1 rows as the table is
//constructed in bottom up manner using the base
//case (n = 0)
int [] table = new int [n+1];
//Initialize all table values as 0
for ( int i = 0; i <table.Length; i++)
{
table[i] = 0;
}
//Base case (If given value is 0)
table[0] = 1;
//Pick all coins one by one and update the table[]
//values after the index greater than or equal to
//the value of the picked coin
for ( int i = 0; i <m; i++)
for ( int j = S[i]; j <= n; j++)
table[j] += table[j - S[i]];
return table[n];
}
//Driver Function
public static void Main()
{
int []arr = {1, 2, 3};
int m = arr.Length;
int n = 4;
Console.Write(countWays(arr, m, n));
}
}
//This code is contributed by Sam007
PHP
<?php
//PHP program for
//coin change problem.
function count1( $S , $m , $n )
{
//We need n+1 rows as
//the table is constructed
//in bottom up manner
//using the base case 0
//value case (n = 0)
$table ;
for ( $i = 0; $i <$n + 1; $i ++)
for ( $j = 0; $j <$m ; $j ++)
$table [ $i ][ $j ] = 0;
//Fill the enteries for
//0 value case (n = 0)
for ( $i = 0; $i <$m ; $i ++)
$table [0][ $i ] = 1;
//Fill rest of the table
//entries in bottom up manner
for ( $i = 1; $i <$n + 1; $i ++)
{
for ( $j = 0; $j <$m ; $j ++)
{
//Count of solutions
//including S[j]
$x = ( $i - $S [ $j ]>= 0) ?
$table [ $i - $S [ $j ]][ $j ] : 0;
//Count of solutions
//excluding S[j]
$y = ( $j>= 1) ?
$table [ $i ][ $j - 1] : 0;
//total count
$table [ $i ][ $j ] = $x + $y ;
}
}
return $table [ $n ][ $m -1];
}
//Driver Code
$arr = array (1, 2, 3);
$m = count ( $arr );
$n = 4;
echo count1( $arr , $m , $n );
//This code is contributed by mits
?>
输出如下:
4
时间复杂度:O(百万)
以下是方法2的简化版本。此处所需的辅助空间仅为O(n)。
C/C++
int count( int S[], int m, int n )
{
//table[i] will be storing the number of solutions for
//value i. We need n+1 rows as the table is constructed
//in bottom up manner using the base case (n = 0)
int table[n+1];
//Initialize all table values as 0
memset (table, 0, sizeof (table));
//Base case (If given value is 0)
table[0] = 1;
//Pick all coins one by one and update the table[] values
//after the index greater than or equal to the value of the
//picked coin
for ( int i=0; i<m; i++)
for ( int j=S[i]; j<=n; j++)
table[j] += table[j-S[i]];
return table[n];
}
Java
public static int count( int S[], int m, int n )
{
//table[i] will be storing the number of solutions for
//value i. We need n+1 rows as the table is constructed
//in bottom up manner using the base case (n = 0)
int table[]= new int [n+ 1 ];
//Base case (If given value is 0)
table[ 0 ] = 1 ;
//Pick all coins one by one and update the table[] values
//after the index greater than or equal to the value of the
//picked coin
for ( int i= 0 ; i<m; i++)
for ( int j=S[i]; j<=n; j++)
table[j] += table[j-S[i]];
return table[n];
}
python
# Dynamic Programming Python implementation of Coin
# Change problem
def count(S, m, n):
# table[i] will be storing the number of solutions for
# value i. We need n+1 rows as the table is constructed
# in bottom up manner using the base case (n = 0)
# Initialize all table values as 0
table = [ 0 for k in range (n + 1 )]
# Base case (If given value is 0)
table[ 0 ] = 1
# Pick all coins one by one and update the table[] values
# after the index greater than or equal to the value of the
# picked coin
for i in range ( 0 , m):
for j in range (S[i], n + 1 ):
table[j] + = table[j - S[i]]
return table[n]
# Driver program to test above function
arr = [ 1 , 2 , 3 ]
m = len (arr)
n = 4
x = count(arr, m, n)
print (x)
# This code is contributed by Afzal Ansari
C#
//Dynamic Programming C# implementation
//of Coin Change problem
using System;
class GFG
{
static int count( int []S, int m, int n)
{
//table[i] will be storing the
//number of solutions for value i.
//We need n+1 rows as the table
//is constructed in bottom up manner
//using the base case (n = 0)
int [] table = new int [n + 1];
//Base case (If given value is 0)
table[0] = 1;
//Pick all coins one by one and
//update the table[] values after
//the index greater than or equal
//to the value of the picked coin
for ( int i = 0; i <m; i++)
for ( int j = S[i]; j <= n; j++)
table[j] += table[j - S[i]];
return table[n];
}
//Driver Code
public static void Main()
{
int []arr = {1, 2, 3};
int m = arr.Length;
int n = 4;
Console.Write(count(arr, m, n));
}
}
//This code is contributed by Raj
PHP
<?php
function count_1( & $S , $m , $n )
{
//table[i] will be storing the number
//of solutions for value i. We need n+1
//rows as the table is constructed in
//bottom up manner using the base case (n = 0)
$table = array_fill (0, $n + 1, NULl);
//Base case (If given value is 0)
$table [0] = 1;
//Pick all coins one by one and update
//the table[] values after the index
//greater than or equal to the value
//of the picked coin
for ( $i = 0; $i <$m ; $i ++)
for ( $j = $S [ $i ]; $j <= $n ; $j ++)
$table [ $j ] += $table [ $j - $S [ $i ]];
return $table [ $n ];
}
//Driver Code
$arr = array (1, 2, 3);
$m = sizeof( $arr );
$n = 4;
$x = count_1( $arr , $m , $n );
echo $x ;
//This code is contributed
//by ChitraNayal
?>
输出如下:
4
感谢Rohan Laishram提出此空间优化版本的建议。
如果发现任何不正确的地方, 或者想分享有关上述主题的更多信息, 请写评论。
参考文献:
http://www.algorithmist.com/index.php/Coin_Change