Open In App

Fixed Coins for Target Sum with Constraint K

Last Updated : 08 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a set of coin denominations the total number of coins (n) and a target amount (target), the task is to determine if it’s possible to make change, for the target amount using k coins. You have one supply of each coin denomination.

Examples:

Input: n = 4, k = 2, Target = 9, Coins [2, 3, 5, 7]
Output: True
Explanation: In this scenario, you have four coin denominations; [2, 3 5 7]. To make change for a target of 9 cents using two coins you can use one coin 2 cents and another coin worth 7 cents. By combining them (2 + 7 =9) you are able to achieve the desired result. Therefore it is indeed possible to make change with two coins for a target amount of 9 cents.

Input: n =3, k =4, Target =12, Coins : [1, 1, 6]
Output: False
Explanation: In this case, there are three coin denominations; [1,1,6]. Unfortunately, it’s not possible to make change, for a target amount of 12 using four coins.

Approach: To solve the problem follow the below idea:

  • The approach we will begin with is a recursive idea. It involves considering all coins to determine the way to make a change for a given amount. In this function, we assess whether it’s possible to make a change, for an amount using a particular number of coins. We have two options for each coin: either use it and subtract its value from the remaining amount or skip it altogether.
  • To optimize this process and prevent calculations we utilize a technique called memoization. We create a 2D array known as ‘dp’ where dp[i][j] indicates whether it’s feasible to make change for ‘j’ cents using precisely ‘i’ coins. Initially all entries in ‘dp’ are assigned a value to signify that the result hasn’t been computed yet. As we compute the result for a specific ‘i’ and ‘j’ we store it in ‘dp’. This allows us to reuse the memoized results, in our function resulting in efficiency.

Follow the steps to solve the problem:

Define a function solve:

  • Check if K is zero and target is zero, in which case we have found a solution and return true.
  • Check if K is less than or equal to zero or target is less than or equal to zero, in which case we can’t form a solution and return false.
  • Check if we have already computed the solution for the current K and target values. If yes, return the precomputed value.
  • Initialize a boolean variable ans to false.
  • Iterate over all the coins and compute the solution recursively by calling solve with updated values of K, target, and dp.
  • Store the computed solution in the dp array for future use and return the value of ans.

In function makeChanges:

  • Initialize a 2D vector dp with dimensions (K + 5) x (target + 5) and initialize all the values to -1.
  • Call the solve function with the initial values of N, K, target, coins, and dp.
  • Return the result returned by the solve function.

Below is the implementation in C++:

C++




// C++ code for the above approach:
#include <iostream>
#include <vector>
 
using namespace std;
 
// Recursive function to solve the problem
bool solve(int N, int K, int target, vector<int>& coins,
           vector<vector<int> >& dp)
{
    // Base cases
    if (K == 0 && target == 0)
        return true;
    if (K <= 0 || target <= 0)
        return false;
    if (dp[K][target] != -1)
 
        // Return memoized result if
        // available
        return dp[K][target];
 
    bool ans = false;
    for (int i = 0; i < N; i++) {
        // Try using each coin and recursively
        // check if it leads to a solution
        ans |= solve(N, K - 1, target - coins[i], coins,
                     dp);
    }
    // Memoize the result and return it
    return dp[K][target] = ans;
}
 
// Function to make change using
// a given number of coins
bool makeChanges(int N, int K, int target,
                 vector<int>& coins)
{
    // Create a memoization table 'dp' to
    // store computed results
    vector<vector<int> > dp(K + 5,
                            vector<int>(target + 5, -1));
 
    // Call the solve function with
    // the initial parameters
    return solve(N, K, target, coins, dp);
}
 
// Drivers code
int main()
{
 
    int n1 = 4;
    int k1 = 2;
    int target1 = 9;
    vector<int> coins1 = { 2, 3, 5, 7 };
    cout << makeChanges(n1, k1, target1, coins1) << endl;
 
    int n2 = 3;
    int k2 = 4;
    int target2 = 12;
    vector<int> coins2 = { 1, 1, 6 };
    cout << makeChanges(n2, k2, target2, coins2) << endl;
 
    return 0;
}


Java




import java.util.Arrays;
 
public class Main {
 
    // Recursive function to solve the problem
    public static boolean solve(int N, int K, int target,
                                int[] coins, int[][] dp)
    {
        // Base cases
        if (K == 0 && target == 0)
            return true;
        if (K <= 0 || target <= 0)
            return false;
        if (dp[K][target] != -1)
            // Return memoized result if available
            return dp[K][target] == 1;
 
        boolean ans = false;
        for (int i = 0; i < N; i++) {
            // Try using each coin and recursively
            // check if it leads to a solution
            ans |= solve(N, K - 1, target - coins[i], coins,
                         dp);
        }
        // Memoize the result and return it
        dp[K][target] = ans ? 1 : 0;
        return ans;
    }
 
    // Function to make change using
    // a given number of coins
    public static boolean
    makeChanges(int N, int K, int target, int[] coins)
    {
        // Create a memoization table 'dp' to
        // store computed results
        int[][] dp = new int[K + 5][target + 5];
        for (int[] row : dp) {
            Arrays.fill(row, -1);
        }
 
        // Call the solve function with
        // the initial parameters
        return solve(N, K, target, coins, dp);
    }
 
    // Drivers code
    public static void main(String[] args)
    {
 
        int n1 = 4;
        int k1 = 2;
        int target1 = 9;
        int[] coins1 = { 2, 3, 5, 7 };
        System.out.println(
            makeChanges(n1, k1, target1, coins1));
 
        int n2 = 3;
        int k2 = 4;
        int target2 = 12;
        int[] coins2 = { 1, 1, 6 };
        System.out.println(
            makeChanges(n2, k2, target2, coins2));
    }
}


Python




def GFG(N, K, target, coins, dp):
    # Base cases
    if K == 0 and target == 0:
        return True
    if K <= 0 or target <= 0:
        return False
    if dp[K][target] != -1:
        # Return memoized result if available
        return dp[K][target] == 1
    ans = False
    for i in range(N):
        # Try using each coin and recursively
        # check if it leads to a solution
        ans |= GFG(N, K - 1, target - coins[i], coins, dp)
    # Memoize the result and return it
    dp[K][target] = 1 if ans else 0
    return ans
# Function to make change using a given number of coins
def make_changes(N, K, target, coins):
    # Create a memoization table 'dp' to
    # store computed results
    dp = [[-1] * (target + 5) for _ in range(K + 5)]
    # Call the solve function with the initial parameters
    return GFG(N, K, target, coins, dp)
# Drivers code
if __name__ == "__main__":
    n1, k1, target1 = 4, 2, 9
    coins1 = [2, 3, 5, 7]
    print(make_changes(n1, k1, target1, coins1))
    n2, k2, target2 = 3, 4, 12
    coins2 = [1, 1, 6]
    print(make_changes(n2, k2, target2, coins2))


C#




// C# code for the above approach:
using System;
using System.Collections.Generic;
 
public class GFG
{
    // Recursive function to solve the problem
    static bool Solve(int N, int K, int target, List<int> coins, bool[,] dp)
    {
        // Base cases
        if (K == 0 && target == 0)
            return true;
        if (K <= 0 || target <= 0)
            return false;
        if (dp[K, target])
            return true;
 
        bool ans = false;
        for (int i = 0; i < N; i++)
        {
            if (target - coins[i] >= 0)
                ans |= Solve(N, K - 1, target - coins[i], coins, dp);
        }
 
        dp[K, target] = ans;
        return ans;
    }
 
    // Function to make change using a given number of coins
    static bool MakeChanges(int N, int K, int target, List<int> coins)
    {
        bool[,] dp = new bool[K + 1, target + 1];
        for (int i = 0; i <= K; i++)
        {
            for (int j = 0; j <= target; j++)
            {
                dp[i, j] = false;
            }
        }
 
        return Solve(N, K, target, coins, dp);
    }
 
    // Drivers code
    public static void Main(string[] args)
    {
        int n1 = 4;
        int k1 = 2;
        int target1 = 9;
        List<int> coins1 = new List<int> { 2, 3, 5, 7 };
        Console.WriteLine(Convert.ToInt32(MakeChanges(n1, k1, target1, coins1)));
 
        int n2 = 3;
        int k2 = 4;
        int target2 = 12;
        List<int> coins2 = new List<int> { 1, 1, 6 };
        Console.WriteLine(Convert.ToInt32(MakeChanges(n2, k2, target2, coins2)));
    }
}


Javascript




// Recursive function to solve the problem
function solve(N, K, target, coins, dp) {
    // Base cases
    if (K === 0 && target === 0) {
        return true;
    }
    if (K <= 0 || target <= 0) {
        return false;
    }
    if (dp[K][target] !== -1) {
        // Return memoized result if available
        return dp[K][target];
    }
 
    let ans = false;
    for (let i = 0; i < N; i++) {
        // Try using each coin and recursively check if it leads to a solution
        ans |= solve(N, K - 1, target - coins[i], coins, dp);
    }
 
    // Memoize the result and return it
    return (dp[K][target] = ans);
}
 
// Function to make change using a given number of coins
function makeChanges(N, K, target, coins) {
    // Create a memoization table 'dp' to store computed results
    const dp = new Array(K + 5).fill().map(() => new Array(target + 5).fill(-1));
 
    // Call the solve function with the initial parameters
    return solve(N, K, target, coins, dp);
}
 
// Driver code
function main() {
    const n1 = 4;
    const k1 = 2;
    const target1 = 9;
    const coins1 = [2, 3, 5, 7];
    console.log(makeChanges(n1, k1, target1, coins1));
 
    const n2 = 3;
    const k2 = 4;
    const target2 = 12;
    const coins2 = [1, 1, 6];
    console.log(makeChanges(n2, k2, target2, coins2));
}
 
// Call the main function
main();


Output

1
0







Time Complexity: O(N * K * target), where N is the size of the coins array, K is the maximum number of coins allowed, and target is the value we are trying to make change for.
Auxiliary Space: O(K * target), which is the size of the 2D dp array we are using for memoization.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads