При заданном значении 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) Растворы, не содержащие mth монеты (или Sm).
2) Растворы, содержащие хотя бы один Sm.
Пусть count (S [], m, n) будет функцией подсчета количества решений, тогда ее можно записать в виде суммы count (S [], m-1, n) и count (S [], m, п-Sm).
Следовательно, задача обладает оптимальным свойством субструктуры, поскольку проблема может быть решена с использованием решений подзадач.
2) Перекрывающиеся подзадачи
Ниже приводится простая рекурсивная реализация проблемы изменения монет. Реализация просто следует рекурсивной структуре, упомянутой выше.
C ++
#include<stdio.h>
int count( int S[], int m, int n )
{
if (n == 0)
return 1;
if (n < 0)
return 0;
if (m <=0 && n >= 1)
return 0;
return count( S, m - 1, n ) + count( S, m, n-S[m-1] );
}
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;
}
|
Джава
import java.io.*;
class GFG {
static int count( int S[], int m, int n )
{
if (n == 0 )
return 1 ;
if (n < 0 )
return 0 ;
if (m <= 0 && n >= 1 )
return 0 ;
return count( S, m - 1 , n ) +
count( S, m, n-S[m- 1 ] );
}
public static void main(String[] args)
{
int arr[] = { 1 , 2 , 3 };
int m = arr.length;
System.out.println( count(arr, m, 4 ));
}
}
|
python3
def count(S, m, n ):
if (n = = 0 ):
return 1
if (n < 0 ):
return 0 ;
if (m < = 0 and n > = 1 ):
return 0
return count( S, m - 1 , n ) + count( S, m, n - S[m - 1 ] );
arr = [ 1 , 2 , 3 ]
m = len (arr)
print (count(arr, m, 4 ))
|
C #
using System;
class GFG
{
static int count( int []S, int m, int n )
{
if (n == 0)
return 1;
if (n < 0)
return 0;
if (m <=0 && n >= 1)
return 0;
return count( S, m - 1, n ) +
count( S, m, n - S[m - 1] );
}
public static void Main()
{
int []arr = {1, 2, 3};
int m = arr.Length;
Console.Write( count(arr, m, 4));
}
}
|
PHP
<?php
function coun( $S , $m , $n )
{
if ( $n == 0)
return 1;
if ( $n < 0)
return 0;
if ( $m <= 0 && $n >= 1)
return 0;
return coun( $S , $m - 1, $n ) +
coun( $S , $m , $n - $S [ $m - 1] );
}
$arr = array (1, 2, 3);
$m = count ( $arr );
echo coun( $arr , $m , 4);
?>
|
Выход :
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) , повторных вычислений с одинаковыми подзадачами можно избежать, построив таблицу временных массивов [] [] по принципу «снизу вверх».
Решение для динамического программирования
C ++
#include<bits/stdc++.h>
using namespace std;
int count( int S[], int m, int n )
{
int i, j, x, y;
int table[n + 1][m];
for (i = 0; i < m; i++)
table[0][i] = 1;
for (i = 1; i < n + 1; i++)
{
for (j = 0; j < m; j++)
{
x = (i-S[j] >= 0) ? table[i - S[j]][j] : 0;
y = (j >= 1) ? table[i][j - 1] : 0;
table[i][j] = x + y;
}
}
return table[n][m - 1];
}
int main()
{
int arr[] = {1, 2, 3};
int m = sizeof (arr)/ sizeof (arr[0]);
int n = 4;
cout << count(arr, m, n);
return 0;
}
|
С
#include<stdio.h>
int count( int S[], int m, int n )
{
int i, j, x, y;
int table[n+1][m];
for (i=0; i<m; i++)
table[0][i] = 1;
for (i = 1; i < n+1; i++)
{
for (j = 0; j < m; j++)
{
x = (i-S[j] >= 0)? table[i - S[j]][j]: 0;
y = (j >= 1)? table[i][j-1]: 0;
table[i][j] = x + y;
}
}
return table[n][m-1];
}
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;
}
|
Джава
import java.util.Arrays;
class CoinChange
{
static long countWays( int S[], int m, int n)
{
long [] table = new long [n+ 1 ];
Arrays.fill(table, 0 );
table[ 0 ] = 1 ;
for ( int i= 0 ; i<m; i++)
for ( int j=S[i]; j<=n; j++)
table[j] += table[j-S[i]];
return table[n];
}
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));
}
}
|
питон
def count(S, m, n):
table = [[ 0 for x in range (m)] for x in range (n + 1 )]
for i in range (m):
table[ 0 ][i] = 1
for i in range ( 1 , n + 1 ):
for j in range (m):
x = table[i - S[j]][j] if i - S[j] > = 0 else 0
y = table[i][j - 1 ] if j > = 1 else 0
table[i][j] = x + y
return table[n][m - 1 ]
arr = [ 1 , 2 , 3 ]
m = len (arr)
n = 4
print (count(arr, m, n))
|
C #
using System;
class GFG
{
static long countWays( int []S, int m, int n)
{
int [] table = new int [n+1];
for ( int i = 0; i < table.Length; i++)
{
table[i] = 0;
}
table[0] = 1;
for ( int i = 0; i < m; i++)
for ( int j = S[i]; j <= n; j++)
table[j] += table[j - S[i]];
return table[n];
}
public static void Main()
{
int []arr = {1, 2, 3};
int m = arr.Length;
int n = 4;
Console.Write(countWays(arr, m, n));
}
}
|
PHP
<?php
function count1( $S , $m , $n )
{
$table ;
for ( $i = 0; $i < $n + 1; $i ++)
for ( $j = 0; $j < $m ; $j ++)
$table [ $i ][ $j ] = 0;
for ( $i = 0; $i < $m ; $i ++)
$table [0][ $i ] = 1;
for ( $i = 1; $i < $n + 1; $i ++)
{
for ( $j = 0; $j < $m ; $j ++)
{
$x = ( $i - $S [ $j ] >= 0) ?
$table [ $i - $S [ $j ]][ $j ] : 0;
$y = ( $j >= 1) ?
$table [ $i ][ $j - 1] : 0;
$table [ $i ][ $j ] = $x + $y ;
}
}
return $table [ $n ][ $m -1];
}
$arr = array (1, 2, 3);
$m = count ( $arr );
$n = 4;
echo count1( $arr , $m , $n );
?>
|
Выход:
4
Сложность времени: O (мн)
Ниже приведен упрощенный вариант метода 2. Требуемое вспомогательное пространство здесь только O (n).
С
int count( int S[], int m, int n )
{
int table[n+1];
memset (table, 0, sizeof (table));
table[0] = 1;
for ( int i=0; i<m; i++)
for ( int j=S[i]; j<=n; j++)
table[j] += table[j-S[i]];
return table[n];
}
|
Джава
public static int count( int S[], int m, int n )
{
int table[]= new int [n+ 1 ];
table[ 0 ] = 1 ;
for ( int i= 0 ; i<m; i++)
for ( int j=S[i]; j<=n; j++)
table[j] += table[j-S[i]];
return table[n];
}
|
питон
def count(S, m, n):
table = [ 0 for k in range (n + 1 )]
table[ 0 ] = 1
for i in range ( 0 ,m):
for j in range (S[i],n + 1 ):
table[j] + = table[j - S[i]]
return table[n]
arr = [ 1 , 2 , 3 ]
m = len (arr)
n = 4
x = count(arr, m, n)
print (x)
|
C #
using System;
class GFG
{
static int count( int []S, int m, int n)
{
int [] table = new int [n + 1];
table[0] = 1;
for ( int i = 0; i < m; i++)
for ( int j = S[i]; j <= n; j++)
table[j] += table[j - S[i]];
return table[n];
}
public static void Main()
{
int []arr = {1, 2, 3};
int m = arr.Length;
int n = 4;
Console.Write(count(arr, m, n));
} }
|
PHP
<?php
function count_1( & $S , $m , $n )
{
$table = array_fill (0, $n + 1, NULl);
$table [0] = 1;
for ( $i = 0; $i < $m ; $i ++)
for ( $j = $S [ $i ]; $j <= $n ; $j ++)
$table [ $j ] += $table [ $j - $S [ $i ]];
return $table [ $n ];
}
$arr = array (1, 2, 3);
$m = sizeof( $arr );
$n = 4;
$x = count_1( $arr , $m , $n );
echo $x ;
?>
|
Выход:
4
Спасибо Рохану Лайшраму за предложение оптимизированной версии.
Ниже приводится упрощенная версия
int count( int S[], int m, int n )
{
int table[m+1][n+1];
memset (table, 0, sizeof (table));
for ( int i=0;i<m;i++)
{table[0][i] = 1;
}
for ( int i=1;i<=m;i++)
{
for ( int j=1;j<=n;j++)
{
if (S[i-1]>j)
{
table[i][j]=table[i-1][j];
}
else
{
table[i][j]=table[i-1][j]+table[i][j-(i-1)];
}
}
}
return table[m][n];
}
|
Выход:
4
Пожалуйста, пишите комментарии, если вы обнаружите что-то неправильное или вы хотите поделиться дополнительной информацией по обсуждаемой выше теме.
Ссылки:
http://www.algorithmist.com/index.php/Coin_Change
Рекомендуемые посты:
Смена монеты | ДП-7
0.00 (0%) 0 votes