📜  生成总和为给定值的最小硬币组合

📅  最后修改于: 2021-09-22 10:23:38             🧑  作者: Mango

给定一个大小为N的数组arr[]表示可用的面额和一个整数X 。任务是找到可用面额的最小硬币数量的任意组合,使得硬币总和为X 。如果可用面额无法获得给定的总和,则打印-1

例子:

朴素的方法:最简单的方法是尝试给定面额的所有可能组合,这样在每个组合中,硬币的总和等于X 。从这些组合中,选择硬币数量最少的组合并打印出来。如果任何组合的总和不等于X ,则打印-1
时间复杂度: O(X N )
辅助空间: O(N)

高效的方法:上述方法可以使用动态规划进行优化,以找到最少的硬币数量。在找到硬币的最小数量时,回溯可用于跟踪使它们的总和等于X所需的硬币。请按照以下步骤解决问题:

  1. 初始化一个辅助数组dp[] ,其中dp[i]将存储使 sum 等于i所需的最小硬币数量。
  2. 使用本文中讨论的方法找出使它们的总和等于X所需的最小硬币数量。
  3. 找到最小硬币数量后,使用回溯技术追踪使用的硬币,使总和等于X
  4. 在回溯中,遍历数组并选择一个小于当前总和的硬币,使得dp[current_sum]等于dp[current_sum – selected_coin]+1 。将选定的硬币存储在一个数组中。
  5. 完成上述步骤后,通过将当前总和作为(current sum – selected coin value)传递再次回溯。
  6. 找到解决方案后,打印所选硬币的数组。

下面是上述方法的实现:

C++
// C++ program for the above approach
 
#include 
using namespace std;
#define MAX 100000
 
// dp array to memoize the results
int dp[MAX + 1];
 
// List to store the result
list denomination;
 
// Function to find the minimum number of
// coins to make the sum equals to X
int countMinCoins(int n, int C[], int m)
{
    // Base case
    if (n == 0) {
        dp[0] = 0;
        return 0;
    }
 
    // If previously computed
    // subproblem occurred
    if (dp[n] != -1)
        return dp[n];
 
    // Initialize result
    int ret = INT_MAX;
 
    // Try every coin that has smaller
    // value than n
    for (int i = 0; i < m; i++) {
 
        if (C[i] <= n) {
 
            int x
                = countMinCoins(n - C[i],
                                C, m);
 
            // Check for INT_MAX to avoid
            // overflow and see if result
            // can be minimized
            if (x != INT_MAX)
                ret = min(ret, 1 + x);
        }
    }
 
    // Memoizing value of current state
    dp[n] = ret;
    return ret;
}
 
// Function to find the possible
// combination of coins to make
// the sum equal to X
void findSolution(int n, int C[], int m)
{
    // Base Case
    if (n == 0) {
 
        // Print Solutions
        for (auto it : denomination) {
            cout << it << ' ';
        }
 
        return;
    }
 
    for (int i = 0; i < m; i++) {
 
        // Try every coin that has
        // value smaller than n
        if (n - C[i] >= 0
            and dp[n - C[i]] + 1
                    == dp[n]) {
 
            // Add current denominations
            denomination.push_back(C[i]);
 
            // Backtrack
            findSolution(n - C[i], C, m);
            break;
        }
    }
}
 
// Function to find the minimum
// combinations of coins for value X
void countMinCoinsUtil(int X, int C[],
                       int N)
{
 
    // Initialize dp with -1
    memset(dp, -1, sizeof(dp));
 
    // Min coins
    int isPossible
        = countMinCoins(X, C,
                        N);
 
    // If no solution exists
    if (isPossible == INT_MAX) {
        cout << "-1";
    }
 
    // Backtrack to find the solution
    else {
        findSolution(X, C, N);
    }
}
 
// Driver code
int main()
{
    int X = 21;
 
    // Set of possible denominations
    int arr[] = { 2, 3, 4, 5 };
 
    int N = sizeof(arr) / sizeof(arr[0]);
 
    // Function Call
    countMinCoinsUtil(X, arr, N);
 
    return 0;
}


Java
// Java program for
// the above approach
import java.util.*;
class GFG{
   
static final int MAX = 100000;
 
// dp array to memoize the results
static int []dp = new int[MAX + 1];
 
// List to store the result
static List denomination =
            new LinkedList();
 
// Function to find the minimum
// number of coins to make the
// sum equals to X
static int countMinCoins(int n,
                         int C[], int m)
{
  // Base case
  if (n == 0)
  {
    dp[0] = 0;
    return 0;
  }
 
  // If previously computed
  // subproblem occurred
  if (dp[n] != -1)
    return dp[n];
 
  // Initialize result
  int ret = Integer.MAX_VALUE;
 
  // Try every coin that has smaller
  // value than n
  for (int i = 0; i < m; i++)
  {
    if (C[i] <= n)
    {
      int x = countMinCoins(n - C[i],
                            C, m);
 
      // Check for Integer.MAX_VALUE to avoid
      // overflow and see if result
      // can be minimized
      if (x != Integer.MAX_VALUE)
        ret = Math.min(ret, 1 + x);
    }
  }
 
  // Memoizing value of current state
  dp[n] = ret;
  return ret;
}
 
// Function to find the possible
// combination of coins to make
// the sum equal to X
static void findSolution(int n,
                         int C[], int m)
{
  // Base Case
  if (n == 0)
  {
    // Print Solutions
    for (int it : denomination)
    {
      System.out.print(it + " ");
    }
    return;
  }
 
  for (int i = 0; i < m; i++)
  {
    // Try every coin that has
    // value smaller than n
    if (n - C[i] >= 0 &&
        dp[n - C[i]] + 1 ==
        dp[n])
    {
      // Add current denominations
      denomination.add(C[i]);
 
      // Backtrack
      findSolution(n - C[i], C, m);
      break;
    }
  }
}
 
// Function to find the minimum
// combinations of coins for value X
static void countMinCoinsUtil(int X,
                              int C[], int N)
{
  // Initialize dp with -1
  for (int i = 0; i < dp.length; i++)
    dp[i] = -1;
 
  // Min coins
  int isPossible = countMinCoins(X, C, N);
 
  // If no solution exists
  if (isPossible == Integer.MAX_VALUE)
  {
    System.out.print("-1");
  }
 
  // Backtrack to find the solution
  else
  {
    findSolution(X, C, N);
  }
}
 
// Driver code
public static void main(String[] args)
{
  int X = 21;
 
  // Set of possible denominations
  int arr[] = {2, 3, 4, 5};
 
  int N = arr.length;
 
  // Function Call
  countMinCoinsUtil(X, arr, N);
}
}
 
// This code is contributed by Rajput-Ji


Python3
# Python3 program for the above approach
import sys
 
MAX = 100000
 
# dp array to memoize the results
dp = [-1] * (MAX + 1)
 
# List to store the result
denomination = []
 
# Function to find the minimum number of
# coins to make the sum equals to X
def countMinCoins(n, C, m):
     
    # Base case
    if (n == 0):
        dp[0] = 0
        return 0
 
    # If previously computed
    # subproblem occurred
    if (dp[n] != -1):
        return dp[n]
 
    # Initialize result
    ret = sys.maxsize
 
    # Try every coin that has smaller
    # value than n
    for i in range(m):
        if (C[i] <= n):
            x = countMinCoins(n - C[i], C, m)
 
            # Check for INT_MAX to avoid
            # overflow and see if result
            #. an be minimized
            if (x != sys.maxsize):
                ret = min(ret, 1 + x)
 
    # Memoizing value of current state
    dp[n] = ret
    return ret
 
# Function to find the possible
# combination of coins to make
# the sum equal to X
def findSolution(n, C, m):
     
    # Base Case
    if (n == 0):
 
        # Print Solutions
        for it in denomination:
            print(it, end = " ")
 
        return
 
    for i in range(m):
 
        # Try every coin that has
        # value smaller than n
        if (n - C[i] >= 0 and
         dp[n - C[i]] + 1 == dp[n]):
 
            # Add current denominations
            denomination.append(C[i])
 
            # Backtrack
            findSolution(n - C[i], C, m)
            break
 
# Function to find the minimum
# combinations of coins for value X
def countMinCoinsUtil(X, C,N):
 
    # Initialize dp with -1
    # memset(dp, -1, sizeof(dp))
 
    # Min coins
    isPossible = countMinCoins(X, C,N)
 
    # If no solution exists
    if (isPossible == sys.maxsize):
        print("-1")
 
    # Backtrack to find the solution
    else:
        findSolution(X, C, N)
 
# Driver code
if __name__ == '__main__':
     
    X = 21
 
    # Set of possible denominations
    arr = [ 2, 3, 4, 5 ]
 
    N = len(arr)
 
    # Function call
    countMinCoinsUtil(X, arr, N)
 
# This code is contributed by mohit kumar 29


C#
// C# program for
// the above approach
using System;
using System.Collections.Generic;
class GFG{
   
static readonly int MAX = 100000;
 
// dp array to memoize the results
static int []dp = new int[MAX + 1];
 
// List to store the result
static List denomination =
            new List();
 
// Function to find the minimum
// number of coins to make the
// sum equals to X
static int countMinCoins(int n,
                         int []C,
                         int m)
{
  // Base case
  if (n == 0)
  {
    dp[0] = 0;
    return 0;
  }
 
  // If previously computed
  // subproblem occurred
  if (dp[n] != -1)
    return dp[n];
 
  // Initialize result
  int ret = int.MaxValue;
 
  // Try every coin that has smaller
  // value than n
  for (int i = 0; i < m; i++)
  {
    if (C[i] <= n)
    {
      int x = countMinCoins(n - C[i],
                            C, m);
 
      // Check for int.MaxValue to avoid
      // overflow and see if result
      // can be minimized
      if (x != int.MaxValue)
        ret = Math.Min(ret, 1 + x);
    }
  }
 
  // Memoizing value of current state
  dp[n] = ret;
  return ret;
}
 
// Function to find the possible
// combination of coins to make
// the sum equal to X
static void findSolution(int n,
                         int []C,
                         int m)
{
  // Base Case
  if (n == 0)
  {
    // Print Solutions
    foreach (int it in denomination)
    {
      Console.Write(it + " ");
    }
    return;
  }
 
  for (int i = 0; i < m; i++)
  {
    // Try every coin that has
    // value smaller than n
    if (n - C[i] >= 0 &&
        dp[n - C[i]] + 1 ==
        dp[n])
    {
      // Add current denominations
      denomination.Add(C[i]);
 
      // Backtrack
      findSolution(n - C[i], C, m);
      break;
    }
  }
}
 
// Function to find the minimum
// combinations of coins for value X
static void countMinCoinsUtil(int X,
                              int []C,
                              int N)
{
  // Initialize dp with -1
  for (int i = 0; i < dp.Length; i++)
    dp[i] = -1;
 
  // Min coins
  int isPossible = countMinCoins(X, C, N);
 
  // If no solution exists
  if (isPossible == int.MaxValue)
  {
    Console.Write("-1");
  }
 
  // Backtrack to find the solution
  else
  {
    findSolution(X, C, N);
  }
}
 
// Driver code
public static void Main(String[] args)
{
  int X = 21;
 
  // Set of possible denominations
  int []arr = {2, 3, 4, 5};
 
  int N = arr.Length;
 
  // Function Call
  countMinCoinsUtil(X, arr, N);
}
}
 
// This code is contributed by shikhasingrajput


Javascript


输出:
2 4 5 5 5

时间复杂度: O(N*X),其中 N 是给定数组的长度,X 是给定的整数。
辅助空间: O(N)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程