DP - Counting coin change - c++

The problem requires to count number of coin changes for a particular cost.
For example, if I have coin values of 50, 20, 10, 5, 1, I can form costs of:
5 => (5), (11111), which are 2 ways.
10 => (10), (5, 5), (5, 11111), (11111, 11111), which are 4 ways.
Here is my function. It is returning wrong results begging from cost of 10 (returns 9 ways while the actual number of ways is only 4)
int dp[10000];
int coins[] = { 50, 20, 10, 5, 1 };
int rec(int n)
{
if (n == 0) return 1;
if (dp[n] != -1) return dp[n];
int cnt = 0;
for (int i = 0; i < 5; i++)
if (coins[i] <= n) cnt += rec(n - coins[i]);
return dp[n] = cnt;
}
How can I fix this function to give the correct number of ways? Is this algorithm correct even? see the complete code and its output here
NOTE: my problem is not with dp array initialization. I am using memset to initialize it to -1 each time before calling rec.

(5, 1, 1, 1, 1, 1) and (1, 1, 1, 5, 1, 1) is different way in you algorithm, you should keep it decreasing.
int dp[10000][5]; // dp[20][2] means, if the biggest coin is coins[2],
// how much ways for 20 ?
int coins[] = { 1, 5, 10, 20, 50 }; // here
int rec(int n, int m)
{
int cnt = 0;
int i;
if (n == 0) return 1;
//if (m == 0) return 1;
if (dp[n][m] != -1) return dp[n][m];
for (i = 0; i <= m; i++)
if (coins[i] <= n) cnt += rec(n - coins[i], i);
return dp[n][m] = cnt;
}
int main()
{
memset(dp, -1, sizeof(dp));
printf("%d\n", rec(10, 4));
}

The result is wrong since you never make sure that your algorithm starts with the 5 coin. (5,11111) is just as valid in your code as (1, 5, 1111), but this is the same result. Your result should be wrong from 6 and higher, not 10 and higher.
To fix this you can do like a cutoff in your function rec():
int rec(int n, int cutoff)
{
if (n == 0) return 1;
if (dp[n] != -1) return dp[n];
int cnt = 0;
for (int i = cutoff; i < 5; i++)
if (coins[i] <= n) cnt += rec(n - coins[i], i);
return dp[n] = cnt;
}
Should do it.
Edit: you will have to take care of your dp[] array, since it does not care about this cutoff, but this in general is the fault you are running into. You could comment that line, and check if this works.

One remark: Your initialization
memset(dp, -1, sizeof dp);
is not really safe. memset initializes every byte of a memory space (see http://www.cplusplus.com/reference/clibrary/cstring/memset/.). For this particular case you are lucky and the representation of int(-1) is (probably) the same of four times unsigned char(-1).
I would suggest using std::fill ( http://www.cplusplus.com/reference/algorithm/fill/ ).

Related

Understanding the recursive knapsack

When I learned recursion, I understood it with 3 steps, where one of them was the assumption step. For example, if I want to find the sum of n integers:
int func(int n)
{
if(n <= 1)
return n;
int ans = func(n-1); //Assumption step
return ans + n;
}
When n = 5, then In the assumption step I assume that func(n-1) ie; func(4) will give me the correct answer 10. So keeping that assumption in mind, I just write return ans + n; Since I know ans has 10 in it and then just add the current n to it, which will give me my answer of 15.
Now when I look at the knapsack code:
int knapsack(int wt[], int val[], int capacity, int n)
{
if (n == 0 || capacity == 0)
return 0;
if(wt[n-1] > capacity)
return knapsack(wt, val, capacity-wt[n-1], n-1);
return max(val[n-1] + knapsack(wt, val, capacity-wt[n-1], n-1), knapsack(wt, val, capacity, n-1));
}
int main()
{
int wt[] = {1, 3, 4, 5};
int val[] = {1, 4, 5, 7};
int capacity = 7;
cout<<knapsack(wt,val,capacity, 4); // gives 9
}
Which function do I trust to give me the solution for the smaller value n-1 and what will it be. How can I apply and understand the assumption step in the knapsack code?

Efficient algorithm to compute combinations with repetitions of an array adding up to given sum

So in a personal C++ project I am faced with a problem. I am rephrasing it as follows :
Given an array of n elements (e.g. [1, 3, 5], with n = 3 elements) where the number at the ith position denotes how many possible values the number at ith index can take (e.g here the first element can take 1 value which is 0; the second element can take 3 values from among 0,1,2; the third element can take 5 values from among 0,1,2,3,4).
I need to list all possible such arrays of length n that sum up to less than or equal to a given number k.
Here is an example :
Input 1:
input array = [2,2];
k = 2
Output 1:
[0,0], [0,1], [1,0], [1,1]
Also, for instance :
Input 2:
input array = [2,2];
k = 1
Output 2:
[0,0], [0,1], [1,0]
The issue :
I have coded up a simple recursive and a simple iterative solution, which enumerates all arrays and only keeps those which have sum less than k. The problem with these is that for the case where n is large and k = 1, my code takes very long to run, since it enumerates all the cases and keeps a few.
I cannot see any overlapping sub-problems so I feel DP and memoization isn't applicable. How can I write the required C++ code for this that works?
Here is my code for the iterative version :
// enumerates all arrays which sum up to k
vector<vector<int> > count_all_arrays(vector<int> input_array, int k){
vector<vector<int> > arr;
int n = (int)input_array.size();
// make auxilliary array with elements
for(int i = 0; i < n; i++){
vector<int> temp(input_array[i]);
std::iota(temp.begin(), temp.end(), 0);
arr.push_back(temp);
}
// computes combinations
vector<int> temp(n);
vector<vector<int> > answers;
vector<int> indices(n, 0);
int next;
while(1){
temp.clear();
for (int i = 0; i < n; i++)
temp.push_back(arr[i][indices[i]]);
long long int total = accumulate(temp.begin(), temp.end(), 0);
if(total <= k)
answers.push_back(temp);
next = n - 1;
while (next >= 0 &&
(indices[next] + 1 >= (int)arr[next].size()))
next--;
if (next < 0)
break;
indices[next]++;
for (int i = next + 1; i < n; i++)
indices[i] = 0;
}
return answers;
}
It's a pretty simple recursive task:
#include <bits/stdc++.h>
using namespace std;
int arr[] = {2, 2};
int n = 2;
int k = 2;
void gen(int pos, int sum, string s){
if(pos == n){
cout<<"["<<s<<" ]"<<endl;
return;
}
for(int i = 0; i < arr[pos]; i++){
if(sum + i > k) return;
gen(pos + 1, sum + i, s + " " + to_string(i));
}
}
int main(){
gen(0, 0, "");
return 0;
}
Just generate all possibilities for each slot of the array and for each choice, take the sum to the evaluation of the next slot.
When n is large and k = 1, it's natural that it takes O(n), since you will have:
[0, 0, 0, ..., 0, 0, 1]
[0, 0, 0, ..., 0, 1, 0]
[0, 0, 0, ..., 1, 0, 0]
...
[0, 0, 1, ..., 0, 0, 0]
[0, 1, 0, ..., 0, 0, 0]
[1, 0, 0, ..., 0, 0, 0]
You should use dp to make it fast in everycase. With dp[i][j] mean how many ways you use first j element to create a sum which is less than or equal i.
dp[i][j] = dp[
for (int l = 0; l <= i; l++)
dp[i][j] += dp[l][j] + min(i-l+1, input[j])
The result is dp[k,n]

Knapsack - How to identify which weights are used?

I have a code which gives the maximum value I can get by filling the knapsack with the optimal set of weights.
int arr[5] = {0, 0, 0, 0, 0};
int Weight[5] = {2, 5, 8, 7, 9};
int Value[5] = {4, 5, 7, 9, 8};
const int n = 5;
const int maxCapacity = 20;
int maximum(int a, int b)
{
return a > b ? a : b;
}
int knapsack(int capacity, int i)
{
if (i > n-1) return 0;
if (capacity < Weight[i])
{
return knapsack(capacity, i+1);
}
else
{
return maximum (knapsack(capacity, i+1),
knapsack(capacity - Weight[i], i+1) + Value[i]);
}
}
int main (void)
{
cout<<knapsack(maxCapacity,0)<<endl;
return 0;
}
I need to extend this solution by printing which all weights are used to find the optimal solution. For this I plan to use an array arr initialized to 0. Whenever a weight is used I mark the corresponding position in arr by 1, otherwise it remains 0.
First thing that came into my mind is to change the maximum() function like shown below
int maximum(int a, int b, int i)
{
if (a > b)
{
if (arr[i] == 1) arr[i] = 0;
return a;
}
else
{
if (arr[i] == 0) arr[i] = 1;
return b;
}
}
But even this solution fails for some combination of weights and values. Any suggestions on how to go forward?
The problem is that you dont know which one of the two options are selected by this command
return maximum (knapsack(capacity, i+1),
knapsack(capacity - Weight[i], i+1) + Value[i]);
I guess you can use two variables to store the values and if the weight is selected( the value of that variable is bigger ) you can add it to the array . Hope that solves your problem.

Function to check if any combination of numbers in a vector will add up to an int?

To start with, I'm looking for something simple and easy to understand rather than the most efficient.
I am trying to create a function that will take in a vector, and an int. The function should return true if any numbers in the vector can add up to the int.
The vector will start with the numbers 1,2,3,4,5,6,7,8,9,10 in it, and throughout the program numbers will be removed. There will be no duplicates of numbers.
The int can be any number from 2 through 12.
Some examples:
vector = { 2,3,4,5 } int = 7; function returns true because 3 + 4 = 7.
vector = { 1,5,8 } int = 7; function returns false because none of these numbers can add to 7.
vector = { 3,6 } int = 3; function returns true because 3 = 3.
vector = { 5 } int = 2; function returns false because five cannot add to two.
This is the very last function I need to finish a game I am working on. I feel like I'm missing an easy solution, but I'm not sure. Can anyone show me how to do this, or point me in the right direction of how to solve this problem? Thank you in advance.
Given the additional information in the comments, the following function should do (I'm assuming the same number cannot be used twice in the sum):
typedef std::vector<int>::iterator iter;
bool contains_sum(iter begin, iter end, int sum)
{
while (begin != end)
{
--end;
if (*end > sum)
continue;
if (contains_sum(begin, end, sum - *end))
return true;
}
return sum == 0;
}
Isn't this a case of the knapsack problem?
See also: subset sum
What you need to do is to find all possible combinations and then check if any of those have the right sum. A double-recursive function can make the check.
bool canFormSum(vector<int>::iterator rest, vector<int>::iterator end,
int sumSoFar, int targetSum)
{
if(rest == end) return false;
if(sumSoFar + *rest == targetSum) return true;
if(canFormSum(rest + 1, end, sumSoFar, targetSum)) return true;
if(sumSoFar + *rest > targetSum) return false;
return canFormSum(rest + 1, end, sumSoFar + *rest, targetSum);
}
It's a nice example of recursive calculation - but for anything but small vectors it has horrible performance.
For the general cases (size of vector > 10),
Let f({a, b, c, d, ...}, e) be the result of whether any number in the set {a, b, c, d, ...} be equal to e.
Observe that, if e = x + y + z + ..., then either (1) a is in the set of {x, y, z, ...}, or (2) a is not in the set of {x, y, z, ...}. That means, we have the recursive definition:
f({a, etc...}, e) = f({etc...}, e-a) || f({etc...}, e)
And obviously, if the sum is 0, the relation is always true by not including any element from the set:
f({...}, 0) = true
and if the set is empty and the sum is nonzero, the relation is always false:
f({}, e) = false (if e != 0)
These are the base cases of the recursion.
Edit: See also the Subset sum problem for further discussion.
Just to compare my (C) solution with celtschk (c++) solution. (Basically compared the approach, not the languages)
#include <iostream>
#include <vector>
using namespace std;
int counter = 0;
typedef std::vector<int>::iterator iter;
bool contains_sum(iter begin, iter end, int sum)
{
counter ++;
while (begin != end)
{
--end;
if (contains_sum(begin, end, sum - *end))
return true;
}
return sum == 0;
}
int main () {
vector<int> data;
for (int i = 1; i <= 30; i ++) {
data.push_back(i);
}
int target = 77;
if (contains_sum (data.begin(), data.end(), target)) {
cout << "possible\n" << counter;
} else {
cout << "not possible\n << counter";
}
}
output
possible
268304387
Means nearly 270 million calls of recursive method
Now my approach
#include<stdio.h>
#include<stdlib.h>
int counter;
int check (int* in, int sum) {
counter ++;
while (1) {
int act = *in++;
if (act == 0) return 0;
int rest = sum - act;
if (rest == 0) return 1; // found;
if (rest > 0) {
if (1 == check (in, rest)) return 1; // found
}
}
return -1;
}
void pr (int* in, int sum) {
counter = 0;
int res = check (in, sum);
while (*in) {
printf ("%d ", *in ++);
}
if (res == 0) {
printf(" != %d %d\n", sum, counter);
} else {
printf(" == %d %d\n", sum, counter);
}
}
int main () {
int p0[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,
11,12,13,14,15,16,17,18,19,20,
21,22,23,24,25,26,27,28,29,30,
0};
pr (p0, 77);
int p1[] = {2,3,4,5, 0};
pr (p1, 7);
int p2[] = {1,5,8, 0};
pr (p2, 7);
int p3[] = {3,6, 0};
pr (p3, 3);
int p4[] = {5, 0};
pr (p4, 2);
int p5[] = {1, 100, 6, 0};
pr (p5, 7);
return 0;
}
and this is the output
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29 30 == 77 22
2 3 4 5 == 7 4
1 5 8 != 7 4
3 6 == 3 1
5 != 2 1
1 100 6 == 7 2
Ups, just 22 iterations!
Anyone may decide which approach to consider more "elegant"
You have to try all possible combination until you found a solution. SUch problems would be good for the language "prolog". So we have to simulate backtracking.
this code is in the end c.
#include<stdio.h>
int check (int* in, int sum) {
while (1) {
int act = *in++;
if (act == 0) return 0;
int rest = sum - act;
if (rest > 0) { // test in the order of expected likelyhoods
if (1 == check (in, rest)) return 1; // found
}
// if (rest < 0) return 0; // minor optimization, valid if list is ordered ascendant
if (rest == 0) return 1; // found;
}
//return -1; // only necessary on poor compilers
}
void pr (int* in, int sum) {
int res = check (in, sum);
while (*in) {
printf ("%d ", *in ++);
}
if (res == 0) {
printf(" != %d\n", sum);
} else {
printf(" == %d\n", sum);
}
}
int main () {
int p1[] = {2,3,4,5, 0};
pr (p1, 7);
int p2[] = {1,5,8, 0};
pr (p2, 7);
int p3[] = {3,6, 0};
pr (p3, 3);
int p4[] = {5, 0};
pr (p4, 2);
int p5[] = {1, 100, 6, 0};
pr (p5, 7);
return 0;
}
proven to run
2 3 4 5 == 7
1 5 8 != 7
3 6 == 3
5 != 2
1 100 6 == 7

A function that returns a digit within a number

I want to create a function which will a number and the position of the digit that I want to retrieve,
int getDigit(int value, int positionFromLeft)
Say, getDigit(534, 2) will return 3.
What could be the easiest / efficient way to write this function?
First, it'll be a lot easier if you're willing to work for the right instead of the left (i.e., from the least significant digit).
Given an input N, N%10 will give the least significant digit. X/10 will shift X one digit to the right, x/100 will shift it two digits to the right, etc.
If you really need to start from the left, log10 should get you the total number of digits.
All these string-based solutions scare me... Really guys? :-/
int getDigit(int value, int positionFromLeft)
{
int posFromRight = 1;
{
int v = value;
while (v /= 10)
++posFromRight;
}
posFromRight -= positionFromLeft - 1;
while (--posFromRight)
value /= 10;
value %= 10;
return value > 0 ? value : -value;
}
Note that passing an out-of-bounds value for positionFromLeft won't return any sensical value as-is.
The easiest is just to convert to a string and do a lookup. This example uses C++, but the idea can easily be translated to C.
int getDigit(int value, int positionFromLeft) {
if (value < 0) positionFromLeft++;
std::stringstream ss;
ss << value;
std::string s = ss.str();
if (positionFromLeft >= 1 && positionFromLeft <= s.length())
return s[positionFromLeft-1] - '0';
else
throw std::runtime_error("invalid digit position");
}
Turns out there are some corner cases to think about here.
What happens if value is negative? I chose to ignore the sign and count from the first digit.
What if the position is out of bounds? I chose to throw an exception.
There is also a possibility of value being INT_MIN, so simply taking the absolute value won't work.
Different recursive solution to this old question (I changed the type of positionFromLeft to unsigned)
int getDigit(int value, unsigned positionFromLeft) {
assert(positionFromLeft > 0);
if (positionFromLeft == 1) return abs(value) % 10;
if (value == 0) return 0; // optimization: break out of recursion if 0 is reached
return getDigit(value / 10, positionFromLeft - 1);
}
See ideone
Simplest but not necessarily the best:
int getDigit(int value, int positionFromLeft)
{
char buf[sizeof(int)*3+2];
if (sprintf(buf, "%d", value)-1U < positionFromLeft-1U) return -1;
return buf[positionFromLeft-1U]-'0';
}
Note: Edited since someone objected (apparently) to snprintf not being in C++, and to account for out-of-bounds and one-based position. Now it's slightly less simple...
function getDigit(original,nonZeroIndexedIndex)
{
return ((int)floor(original / pow(10, nonZeroIndexedIndex))) % 10;
}
with #R..'s suggestion:
function getDigit(original,nonZeroIndexedIndex)
{
int tens [5] = { 1, 10, 100, 1000, 10000 };
return ((int)floor(original / tens[nonZeroIndexedIndex - 1])) % 10;
}
Hope this helps! This is a nice little C++ refresher for me :)
If you really need to count from left, you can do this:
uint8_t getDigitR(uint16_t value, uint8_t i) {
uint32_t digit = 1;
while (digit <= value)
digit *= 10;
while (i--) // if you start counting at 1
digit /= 10;
return (value / digit) % 10;
}
But this is probably not really more efficient or easier than string solutions, but since it is homework, there might be a few algebraic things to learn if not done with strings :)
However, you need less stack space.
int getDigit(int value, int positionFromLeft)
{
char buffer[20];
if (value > 0)
value = -value;
int len = snprintf(buffer, sizeof(buffer), "%d", value);
int digit = 0;
if (len > positionFromLeft && positionFromLeft > 0)
digit = buffer[positionFromLeft] - '0';
return digit;
}
This returns zero if you ask for a digit beyond the RHS of the number. The negation trick ensures that the value is always negative (and never runs into problems with negating INT_MIN), and then there is a minus sign so the positionFromLeft is correct without adjusting by one. This code assumes C99 or C++ (with the minor caveat that snprintf() is not mandated by C++98 but is likely to be available as an extension; a pure C++98 and C99 solution would have to use sprintf() instead, which in context is safe enough).
Protest over the solution that was at one time selected as correct!
Consider the test harness:
#include <stdio.h>
int getDigit1(int value, int positionFromLeft)
{
while (--positionFromLeft)
value /= 10;
return value % 10;
}
int getDigit2(int value, int positionFromLeft)
{
char buffer[20];
if (value > 0)
value = -value;
int len = snprintf(buffer, sizeof(buffer), "%d", value);
int digit = 0;
if (len > positionFromLeft && positionFromLeft > 0)
digit = buffer[positionFromLeft] - '0';
return digit;
}
int main(void)
{
int values[] = { 534, 1234567, -1234567 };
for (int i = 0; i < 3; i++)
{
for (int j = 1; j <= 7; j++)
printf("getDigit(%d, %d) = (v1) %d, (v2) %d\n", values[i], j,
getDigit1(values[i], j), getDigit2(values[i], j));
putchar('\n');
}
return 0;
}
This solution produces the correct value for getDigit(534, 2) and getDigit(1234567, 4) (and, generally, the middle digit of a number that has an odd number of digits) but is otherwise incorrect:
getDigit(534, 1) = (v1) 4, (v2) 5
getDigit(534, 2) = (v1) 3, (v2) 3
getDigit(534, 3) = (v1) 5, (v2) 4
getDigit(534, 4) = (v1) 0, (v2) 0
getDigit(534, 5) = (v1) 0, (v2) 0
getDigit(534, 6) = (v1) 0, (v2) 0
getDigit(534, 7) = (v1) 0, (v2) 0
getDigit(1234567, 1) = (v1) 7, (v2) 1
getDigit(1234567, 2) = (v1) 6, (v2) 2
getDigit(1234567, 3) = (v1) 5, (v2) 3
getDigit(1234567, 4) = (v1) 4, (v2) 4
getDigit(1234567, 5) = (v1) 3, (v2) 5
getDigit(1234567, 6) = (v1) 2, (v2) 6
getDigit(1234567, 7) = (v1) 1, (v2) 7
getDigit(-1234567, 1) = (v1) -7, (v2) 1
getDigit(-1234567, 2) = (v1) -6, (v2) 2
getDigit(-1234567, 3) = (v1) -5, (v2) 3
getDigit(-1234567, 4) = (v1) -4, (v2) 4
getDigit(-1234567, 5) = (v1) -3, (v2) 5
getDigit(-1234567, 6) = (v1) -2, (v2) 6
getDigit(-1234567, 7) = (v1) -1, (v2) 7
The question specifically asks for the Nth digit from the LEFT of the number, counting from 1.
Just to be different, one with no #include needed.
int getDigit(unsigned int original, unsigned int positionFromLeft)
{
if (original==0 && positionFromLeft==1) {
/* In a more mathematical world, zero has no digits. */
return 0;
}
unsigned int expon=0;
unsigned int power=1;
for (unsigned int quotient=original; quotient; quotient/=10, ++expon) {
if (expon >= positionFromLeft) {
power *= 10;
}
}
if (positionFromLeft > expon) {
/* Not enough digits in number. */
return -1;
}
return (original / power) % 10;
}
Correct me if i am wrong.
You can try using sprintf to cast the int to a string representations.
Then have a pointer (say *ptr) point to the first position.
Let positionFromLeft be the position of the character that you want to extract.
Using,
*(ptr + positionFromLeft)
will give you the required digit.
Hope that helps.
I think this is the easiest solution:
int valuePosition(int value, int position) {
int r;
for(int i=0; i<=position; i++){
r = value % 10;
value = value / 10;
}
return r;
}
The first position is 0, if you want that starts in 1 change i<=position with 1
Add to the Number class an instance method called getDigit with the following signature:
int getDigit (int digitNum)
When the digitNum variable specifies the digit number (0) for the unity series, 1 for the tens digit
And so on. The method will return the appropriate digit if such a digit exists. Otherwise the method will return
.-1
.-1 will return digitNum = 6 and for 4 return the digitNN = 3 method for: value = 124571 if, to
List item