Skip to content

Commit b8ffbf7

Browse files
authored
Added English Tutorial for LOJ 1231 - Coin Change I (en) (#428)
* Added English Tutorial for LOJ1231 CoinChangeI(en) * Update en.md
1 parent d2deb7e commit b8ffbf7

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

1231/en.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
## Understanding The Problem Statement
2+
3+
First we identify what the problem wants, we have n coin denomination or values A<sub>i</sub> where for my approach we take i as 0<=i<=n
4+
and n has the constraint 1<=n<=50, and each of the coin with value A is given a count or the number of these coins we have, which is C<sub>i</sub>. We are also provided
5+
K which is the value we wish to pay off using a valid coin combination.
6+
7+
The question simply asks us to find the number of ways by which we can pay off the required value using our available coins.
8+
9+
## Prerequisites
10+
11+
- Basic Understanding of DP(Dynamic Programming) [DP-1 Jenny CS IT](https://youtu.be/lVR2u9lsxl8)
12+
- Preliminary Idea of Coin Change Problem [DP#2 Jenny CS IT](https://youtu.be/L27_JpN6Z1Q)
13+
14+
## Solution Approach
15+
16+
This problem is essentially a variation of the classic dynamic programming problem, coin change. Here we first recognize that we need to store the values for the coin denominations
17+
and the number of each of these coin types in two seperate arrays. Then we define the following formal definition of a recursive function:
18+
19+
coinchange(index,current_value): returns the number of ways by which we can pay off the target cost with the given coin denominations, and number of coins of each type
20+
21+
coinchange(index,current_value): {
22+
1 if current_value=0
23+
0 if i=n(since we are using 0-based indexing)
24+
coinchange<sub>ix</sub>(i+1,current_value-ix\*A<sub>i</sub>) if 0<=ix<=C[i] and 0<=i<n
25+
}
26+
To explain this, we have two base cases if the current value becomes 0 then we return 1 as it represents 1 valid combination
27+
and if the index approaches becomes n we return 0 as we went out of the bounds of the array we initialized or out of bounds of the n we were given but still could not
28+
find a soltuion. The last statement involves a for loop from ix=0 upto ix<=C[i] being the number of coins of type A[i] we have and upon selecting each coin we make
29+
a recursive call to the next coin. A sample recursion tree is given below
30+
![RecursionTreeForMentionedImplementation](https://github.com/mirzaazwad/Competitive-Programming/blob/main/CategoryWisePersonalNotesTutorialsAndProblemsSolved/Dynamic%20Programming/Implementation/RecursionTree.jpg)
31+
The test case for the given diagram is A={1,2,5} and C={3,2,2}.
32+
In the tree above we can see upon each call the child branches or the recursive calls direct to all possible combinations, starting from one coin if ix=0 we don't select
33+
that coin and move forward to the next coin, if ix=1 we select one of that specific coin and then move forward by substracting the total of the selected coins
34+
from the current value upon moving forward by making another recursive call. In this manner if ix=a we select a coins and then move to the next possible selection. In this
35+
manner we can check all possible combinations. But it is not necessary to brute force through all possible combinations. We can eliminate some of the redundant or
36+
repetitive calls by the use of [memoization](https://en.wikipedia.org/wiki/Memoization) which is essentially the process of storing computational results to prevent
37+
recalculating them which might cause unnecessary reptitive computation as mentioned earlier. This can be done using a 2-state dp, the states tend to be reflected by
38+
the number of arguments passed to the defined function which in this case is 2. So here we would take a 2D array with the size of rows as the maximum possible value for n +1 and
39+
columns as the maximum possible value for K +1. In each computation, we store the value result in the dp array as per **dp\[index]\[current_value]**. In future computations,
40+
if we find that the dp array contains our desired value we return it. Initially we set all the values to -1 in the dp array to easily identify if there is a result stored
41+
for that specific combination of index and current_value. A sample implementation is given below:
42+
43+
## Solution
44+
```cpp
45+
#include<bits/stdc++.h>
46+
using namespace std;
47+
#define ll long long
48+
#define INF 100000009
49+
#define modulo 100000007
50+
#define Max_n 55
51+
#define Max_K 1005
52+
#define Max_C 25
53+
int n;
54+
ll K;
55+
vector<ll>A,C;
56+
57+
int dp[Max_n][Max_K];
58+
59+
ll coinchange(int i,int current_value){
60+
if(current_value==0){
61+
return 1;
62+
}
63+
if(i==n){
64+
return 0;
65+
}
66+
if(dp[i][current_value]!=-1){
67+
return dp[i][current_value];
68+
}
69+
dp[i][current_value]=0;
70+
for(int ix=0;ix<=C[i] && current_value-ix*A[i]>=0;ix++){
71+
dp[i][current_value]+=(coinchange(i+1,current_value-ix*A[i])%modulo);
72+
}
73+
return dp[i][current_value]%modulo;
74+
75+
}
76+
77+
78+
void run_test_case(){
79+
memset(dp,-1,sizeof(dp));
80+
cin>>n>>K;
81+
A.resize(n);
82+
C.resize(n);
83+
for(ll &i:A){
84+
cin>>i;
85+
}
86+
for(ll &i:C){
87+
cin>>i;
88+
}
89+
cout<<coinchange(0,K)<<endl;//we pass our desired value that being K to the function as the current_value, this value is changed in every recursive call
90+
}
91+
92+
int main(void){
93+
int number_of_test_cases;
94+
cin>>number_of_test_cases;
95+
for(int current_case=1;current_case<=number_of_test_cases;current_case++){
96+
cout<<"Case "<<current_case<<": ";
97+
run_test_case();
98+
}
99+
}
100+
```
101+

0 commit comments

Comments
 (0)