给定零钱数量,_最小零钱| 查找可产生给定值的最小硬币数量

这是一个关于找零问题的算法讨论,提供了递归和动态规划两种方法解决如何用最少的硬币组合成给定价值的问题。通过递归解决方案和动态规划(自上而下与自下而上)来计算达到目标值所需的最小硬币数量,以避免重复计算并优化效率。
摘要由CSDN通过智能技术生成

给定零钱数量,

Problem statement:

问题陈述:

Given a value V, if we want to make change for V cents, and we have infinite supply of each of C = { C1, C2, .. , Cm} valued coins, what is the minimum number of coins to make the change?

给定一个值V ,如果我们想以V cents进行找零,而我们有C = {C1,C2,..,Cm}个有价硬币的无限供应,那么进行找零的最小硬币数目是多少?

Input:

输入:

The test case consists of V and N, V is the value of cents and N is the number of coins. The second line of each test case contains N input C[i], the value of available coins.

测试用例由VN组成V是美分的值, N是硬币的数量。 每个测试用例的第二行包含N个输入C [i] ,即可用硬币的值。

Output:

输出:

Print the minimum number of coins to make the change, if not possible print "-1".

打印进行更改的最小硬币数量,如果不可能,请打印“ -1”。

Example with explanation:

带有说明的示例:

    Input: 
    N=5, V = 25
    coins[] = {4,5,2,1,9}.

    Output: 
    Minimum 4 coins required
    We can use one coin of 5 cents, 
    two coins of 9 cents and one of 2 cents
    (9+9+2+5)

    Input: 
    N=6, V = 256324
    coins[] = {1,2,5,10,20,50}. 

    Output: 
    Minimum 5129 coins required

Solution Approach

解决方法

1) Recursive solution

1)递归解决方案

We will start the solution with initially sum = V cents and at each iteration find the minimum coins required by dividing the problem into subproblems where we take {C1, C2, ..., CN} coin and decrease the sum V.

我们将以最初的总和= V cents开始求解,并在每次迭代时将问题划分为子问题,从而求出所需的最小硬币,在这些子问题中,我们拿{C1,C2,...,CN}硬币并减少总和V。

By C[i] (based on the coin we took). Whenever V becomes 0, this means we have a possible or otherwise there is no solution and we return -1;

C [i] (基于我们所使用的硬币)。 每当V变为0时,这意味着我们有可能,否则就没有解决方案,而我们返回-1;

Solution: To find the optimal answer, we return the minimum of all answers for which N became 0.

解决方案:要找到最佳答案,我们返回N变为0的所有答案中的最小值。

If V == 0, then 0 coins required.

如果V == 0 ,则需要0个硬币。

We calculate the total required number of coins using the following function:

我们使用以下函数计算所需的硬币总数:

    int mincoins(coins array[], size of the array, required sum);

So, initially the function call would be:

因此,最初的函数调用为:

    int mincoins(C,N,V);

Where C is the coins array, N is the size of the coin array and V is the required sum.

其中C是硬币阵列, N是硬币阵列的大小, V是所需的总和。

Now our idea is the get the minimum number of coins from the given array
and if the sum that we want to get if not possible from the given set of coins we will return -1.

现在我们的想法是从给定的数组中获得最小数量的硬币
如果不可能从给定的一组硬币中获得总和,我们将返回-1。

So, let's see the function definition:

因此,让我们看一下函数定义:

Function:

功能:

    Mincoins(int coins[],int N,int V):
	    if V==0,then 0 coins are required
	    if V>0:
	        mincoins{V,coins[0...N-1]}=min{1+mincoins{N-coins[i],coins[0...N-1]}}
            Where, i varies from 0 to N-1 and coins<=N
    End Function

Pseudo Code:

伪代码:

    int Mincoins(coins[],N,V):
	    if(V==0)
		    return 0 //base case
	    else{
		    res=INT_MAX //if res=INT_MAX==-1 in the answer
		    for(i=0;i<N;i++){
			    sub;
			    if(coins[i]>=V){ 
				    // recursive call
                    sub=1+mincoins(coins,N,V-coins[i]) 
				    // assigning the min value to res
                    res=min(res,subres) 
			    }
		    }
		    return res//return the result of mincoins.
	    }

The recursive definition consists of the part:

递归定义包括以下部分:

    mincoins{V,coins[0...N-1]}=min{1+mincoins{N-coins[i],coins[0...N-1]}}

This recursive part will generate a recursion tree where we can find many overlapping subproblems, hence we would solve by dynamic programming.

该递归部分将生成一个递归树,在这里我们可以找到许多重叠的子问题,因此可以通过动态编程来解决。

C++ Implementation:

C ++实现:

#include <bits/stdc++.h>
using namespace std;

int mincoins(int C[], int N, int V)
{
    if (V == 0)
        return 0;
    int res = INT_MAX;
    for (int i = 0; i < N; i++) {
        int sub;
        if (V >= C[i]) {
            sub = 1 + mincoins(C, N, V - C[i]);
            res = min(res, sub);
        }
    }
    return res;
}

int main()
{
    cout << "Enter number of test cases: ";
    int t;
    cin >> t;
    
    while (t--) {
        int N, V;
        
        cout << "Enter the size of Coins array: ";
        cin >> N;
        
        int C[N];
        cout << "Enter the coins: ";
        for (int i = 0; i < N; i++)
            cin >> C[i];
            
        cout << "Enter V (Required sum): ";
        cin >> V;
        
        int res = INT_MAX;
        res = mincoins(C, N, V);
        if (res == INT_MAX or res < 0) {
            cout << "NOT POSSIBLE: ";
            cout << -1;
        }
        else {
            cout << "Required coins: ";
            cout << res << "\n";
        }
    }
    return 0;
}

Output

输出量

Enter number of test cases: 3 
Enter the size of Coins array: 3 
Enter the coins: 5 25 10
Enter V (Required sum): 20 
Required coins: 2 
Enter the size of Coins array: 4 
Enter the coins: 9 5 6 1
Enter V (Required sum): 13 
Required coins: 3 
Enter the size of Coins array: 3 
Enter the coins: 7 6 8  
Enter V (Required sum): 9  
NOT POSSIBLE: -1 

2) Dynamic Programming Approach

2)动态编程方法

Since the same subproblems are called, again and again, this problem has Overlapping Subproblems property.

由于一次又一次调用了相同的子问题,因此此问题具有“重叠子问题”属性。

Like other typical Dynamic Programming (DP) problems, re-computations of the same subproblems can be avoided by constructing a temporary array dp[] and memorizing the computed values in this array.

像其他典型的动态编程(DP)问题一样,可以通过构造临时数组dp []并将计算值存储在该数组中来避免相同子问题的重新计算。

We will declare a dp[] array of length equal to the sum required+1 since indexing starts from 0, we will use Top-Down DP, use memoization plus recursion approach.

由于索引从0开始,我们将声明一个dp []数组,该数组的长度等于所需的总和+1,因为索引从0开始,我们将使用自上而下的DP,使用记忆加递归方法。

Initially, we will fill the dp[] array with -1 so that during recursion call if the array if not -1 then we don't have to calculate the value we just need to return the dp[value](memoized array), else we will call the function and fill the required value of the array.

最初,我们将用-1填充dp []数组,以便在递归调用期间,如果该数组不是-1,则不必计算值,我们只需要返回dp [value] (存储数组),否则,我们将调用该函数并填充所需的数组值。

2.1) Top Down Approach

2.1)自上而下的方法

pseudo code:

伪代码:

    int mincoins(coins[],dp[],N,m){
	    // where N is the size if coins array and m is the value 
	    // of cents for which we are calculating the number of coins.

	    if(dp[m]!=-1)	//if we have already solved the subproblem
		    return dp[m]	//directly return the memoized value.
	    if(m==0)	//base case
		    return 0

	    res=INT_MAX //initializ the result
	    for(i=0;i<N;i++){
		    if(coins[i]<=m){
			    sub=1+mincoins(coins,dp,m-coins[i])
			    //recursive  call				
			    if(res>sub)
			    res=min(res,sub)	
		    }
	    }
	    dp[m]=res
	    return dp[m]	
    }

C++ Implementation:

C ++实现:

#include <bits/stdc++.h>
using namespace std;

int mincoins(int coins[], int N, int dp[], int V)
{
    if (dp[V] != -1)
        return dp[V];
    if (V == 0)
        return 0;
    else {
        int res = 1000000009;
        for (int i = 0; i < N; i++) {
            if (V >= coins[i]) {
                int sub = 1 + mincoins(coins, N, dp, V - coins[i]);
                res = min(res, sub);
            }
        }
        dp[V] = res;
    }
    return dp[V];
}

int main()
{
    int t;
    
    cout << "Enter number of test cases: ";
    cin >> t;
    
    while (t--) {
        int N, V;
        
        cout << "Enter size of coins array: ";
        cin >> N;
        
        int coins[N];
        cout << "Enter coins: ";
        for (int i = 0; i < N; i++)
            cin >> coins[i];
            
        cout << "Enter V (required sum): ";
        cin >> V;
        
        int dp[V + 1];
        for (int i = 0; i <= V; i++)
            dp[i] = -1;
        
        dp[0] = 0;
        dp[V] = mincoins(coins, N, dp, V);
        
        if (dp[V] == 1000000009) {
            cout << "Not Possible: ";
            cout << -1 << "\n";
        }
        else {
            cout << "Required coins: ";
            cout << dp[V] << "\n";
        }
    }
    return 0;
}

Output

输出量

Enter number of test cases: 3 
Enter size of coins array: 3  
Enter coins: 5 25 10 
Enter V (required sum): 20 
Required coins: 2 
Enter size of coins array: 4  
Enter coins: 9 5 6 1 
Enter V (required sum): 13 
Required coins: 3 
Enter size of coins array: 3  
Enter coins: 7 6 8
Enter V (required sum): 9  
Not Possible: -1 

2.2) Bottom Up Approach

2.2)自下而上的方法

ith state of dp : dp[i] : Minimum number of coins required to sum to i cents.

dp的 i 状态: dp [i] :总和为i分所需的最小硬币数量。

In this approach, we move from the base case to the desired value of the sum
base dp[0]=0 , where for 0 cents of value we need 0 coins.

在这种方法中,我们从基本情况转到总和的期望值
base dp [0] = 0 ,其中对于0分钱的价值,我们需要0个硬币。

Initially, we will fill the dp[] array with INT_MAX and dp[0]=0 as for 0 cents we need 0 coins.

最初,我们将INT_MAXdp [0] = 0填充到dp []数组中,因为0美分需要0个硬币。

Then we will iterate from 1 cent required sum to V value cents.

然后,我们将从所需的1美分迭代到V值美分。

we will use the outer loop for sum array and inner loop for coins array.

我们将外循环用于求和数组,将内循环用于硬币数组。

Pseudo Code:

伪代码:

    int minCoins(int coins[],int dp[],int N, int V)
    {
	    // Initializing all values to infinity i.e. minimum coins to make any
	    // amount of sum is INT_MAX
	    for(i = 0;i<=N;i++)
		    dp[i] = INF

	    // Base case i.e. minimum coins to make sum = 0 cents is 0
	    dp[0] = 0;

	    // Iterating in the outer loop for possible values of sum between 1 to V
	    // Since our final solution for sum = N might depend upon any of these values
	    for(i=1;i<=V;i++){
		    // Inner loop denotes the index of coin array.
		    // For each value of sum, to obtain the optimal solution.
		    for(j = 0;j<N;j++){
			    // i —> sum
			    // j —> next coin index
			    // If we can include this coin in our solution
			    if(coins[j] <= i){
				    // Solution might include the newly included coin.
				    dp[i] = min(dp[i], 1 + dp[i - coins[j]])
			    }
		    }
	    }
	    //for(i = 1;i<=N;i++)
	    return dp[N];
    }

The overall Time complexity of this approach is O(N*V).

此方法的整体时间复杂度为O(N * V)

C++ Implementation:

C ++实现:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int t;

    cout << "Enter number of test cases: ";
    cin >> t;

    while (t--) {
        int N, V;

        cout << "Enter size of coins array: ";
        cin >> N;

        int coins[N];
        cout << "Enter coins: ";
        for (int i = 0; i < N; i++)
            cin >> coins[i];

        cout << "Enter V (required sum): ";
        cin >> V;
        
        int dp[V + 1];
        for (int i = 0; i <= V; i++)
            dp[i] = 1000000009;
        
        dp[0] = 0;
        
        for (int i = 1; i <= V; i++) {
            for (int j = 0; j < N; j++) {
                if (i >= coins[j]) {
                    dp[i] = min(dp[i], 1 + dp[i - coins[j]]);
                }
            }
        }
        
        if (dp[V] == 1000000009) {
            cout << "Not Possible: ";
            cout << -1 << "\n";
        }
        else {
            cout << "Required coins: ";
            cout << dp[V] << "\n";
        }
    }
    return 0;
}

Output

输出量

Enter number of test cases: 3 
Enter size of coins array: 3  
Enter coins: 5 25 10 
Enter V (required sum): 20 
Required coins: 2 
Enter size of coins array: 4  
Enter coins: 9 5 6 1 
Enter V (required sum): 13 
Required coins: 3 
Enter size of coins array: 3  
Enter coins: 7 6 8
Enter V (required sum): 9  
Not Possible: -1  


翻译自: https://www.includehelp.com/icp/minimum-coin-change-find-minimum-number-of-coins-that-make-a-given-value.aspx

给定零钱数量,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值