Multiple Constrain Knapsack - c++

I'm trying to solve the following problem:
INPUT:
An array of items, each item has 3 different weights (integers), a value and the amount available of this type of item.
A maximum for each type of weight
OUTPUT:
An array that tells how many of each item to take in order to achieve the maximum value. The sum of each of the weights of every item must not exceed the maximum allowed and you may not take more of an item of what is available.
Example output: {3,0,2,1} means 3 of item1, 0 of item2, 2 of item3, and 1 of item4.
Example scenario:
In case I wasn't very clear with the explanation, imagine it's about putting food on a backpack. Each type of food has a weight, a volume, a number of calories and a value and there's a certain amount of each type of food available. The objective would be to maximize the value of the food in the backpack without exceeding a certain maximum amount of weight, volume and calories.
On this scenario the INPUT could be:
Array<Food>:
Burger (Weight 2, Volume 2, Calories 5, Value 5$, number of Burgers 3)
Pizza (Weight 3, Volume 7, Calories 6, Value 8$, number of Pizzas 2)
Hot Dog (Weight 1, Volume 1, Calories 3, Value 2$, number of Hot Dogs 6)
int MaxWeight = 10; int MaxVolume = 15; int MaxCalories = 10;
My Attempt
Since the data set is quite small (say 7 types of items and there's no more than 15 pieces of each item available), I thought of a brute force search:
Keep track of the best set found so far (Most value and doesn't
exceed any limits), call best set B
Have a recursive function R(s) which takes a set (array of how many of each item) as input, if the input is invalid, it returns. If the input is valid it first updates B (in case s better than B) and then calls R(s + p_i) for every product p_i
The idea is to first call R(s) with s = empty set (0 for every product) and every possible branch will be created while the branches that exceed the weights are ignored.
This obviously didn't work cause the amount of branches that have to be checked is huge even for only as few as 7 items
Any help is much appreciated!

You have to consider each type of weight in your DP method. I'll write the implementation in C++:
vector<Food> Array;
int memo[MAX_ITEM][MAX_WEIGHT1][MAX_WEIGHT2][MAX_WEIGHT3];
int f(int ind, int weight1, int weight2, int weight3){
if(weight1<0 || weight2<0 || weight3<0) return -INF;
if(ind == Array.size()) return 0;
int &ret= memo[ind][weight1][weight2][weight3];
if(ret>0) return ret;
int res = 0;
for(int i=0;i<=Array[ind].maxOfType;i++)
res = max(res, i * Array[ind].value + f(ind+1, weight1-i*Array[ind].weight1, weight2-i*Array[ind].weight2, weight3-i*Array[ind].weight3));
return ret = res;
}
The DP function is recursive and we use memoization to optimize it. It returns the maximum value we can get. you can call it by:
f(0,MaxWeight1, MaxWeight2, MaxWeight3);
After that we have to track and see which items leads to maximum value. The Next method will print what you want:
void printResult(int ind, int weight1, int weight2, int weight3){
if(ind == Array.size()) return;
int maxi = memo[ind][weight1][weight2][weight3];
for(int i=0;i<=Array[ind].maxOfType;i++){
int cur = i * Array[ind].value + f(ind+1, weight1-i*Array[ind].weight1, weight2-i*Array[ind].weight2, weight3-i*Array[ind].weight3);
if(cur == maxi){
cout<<i<<", ";
printResult(ind+1, weight1-i*Array[ind].weight1, weight2-i*Array[ind].weight2, weight3-i*Array[ind].weight3);
break;
}
}
}
All codes are tested and works well.

Related

Using modulus to solve coin change question

I'm looking for a different way to solve coin change problem using modulus. Most solutions refer to use of dynamic memory to solve this.
Example:
You are given coins of different denominations and a total amount of
money amount. Write a function to compute the fewest number of coins
that you need to make up that amount. If that amount of money cannot be
made up by any combination of the coins, return -1.
Input: coins = [1, 2, 5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
The goal is to create a solution using modulus instead.
Here is what I've tried so far. I'm wondering if my variable should be initialized to something other than 0 or I'm updating in the wrong part of the code block.
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int pieces = 0;
int remainder = 0;
for(int i = coins.size()-1; i = 0; i--) {
if (amount % coins[i] == 0)
{
pieces += amount/coins[i];
} else {
pieces += amount/coins[i];
remainder = amount%coins[i];
amount = remainder;
}
}
return pieces;
}
}
I'm expecting the output as above. Stuck and not sure what else to try to get this to work.
I understand what you're trying to do, but your code isn't actually going to accomplish what you think it will. Here's a breakdown of your code:
int coinChange(vector<int>& coins, int amount) {
// Minimum number of coins to sum to 'amount'
int pieces = 0;
int remainder = 0;
// Assuming 'coins' is a non-decreasing vector of ints,
// iterate over all coins, starting from the larger ones,
// ending with the smaller ones. This makes sense, as it
// will use more coins of higher value, implying less
// coins being used
for(int i = coins.size()-1; i = 0; i--) {
// If what's left of the original amount is
// a multiple of the current coin, 'coins[i]',
if (amount % coins[i] == 0)
{
// Increase the number of pieces by the number
// of current coins that would satisfy it
pieces += amount/coins[i];
// ERROR: Why are you not updating the remaining amount?
} else {
// What's left of the original amount is NOT
// a multiple of the current coin, so account
// for as much as you can, and leave the remainder
pieces += amount/coins[i];
remainder = amount%coins[i];
amount = remainder;
}
}
// ERROR: What if amount != 0? Should return -1
return pieces;
}
If you fixed the ERRORs I mentioned above, the function would work ASSUMING that all ints in coins behave as the following:
If a coin, s, is smaller than another coin, l, then l must be a multiple of s.
Every coin has to be >= 1.
Proof of 1:
If a coin, s, is smaller than another coin, l, but l is not a multiple of s, using l as one of the coins in your solution might be a bad idea. Let's consider an example, where coins = [4, 7], and amount = 8. You will iterate over coins in non-increasing order, starting with 7. 7 fits into 8, so you will say that pieces = 1, and amount = 1 remains. Now, 4 doesn't fit into amount, so you don't add it. Now the for-loop is over, amount != 0, so you fail the function. However, a working solution would have been two coins of 4, so returning pieces = 2.
Proof of 2:
If a coin, c is < 1, it can be 0 or less. If c is 0, you will divide by 0 and throw an error. Even more confusingly, if you changed your code you could add an infinite amount of coins valued 0.
If c is negative, you will divide by a negative, resulting in a negative amount, breaking your logic.

Greedily assigning scores to maximize the final result

You are given a time line of T days and a list of N scores. You have to assign each score to a day(among 1 to T) such that the total assigned score maximizes.
Although there are restrictions. Each score can be assigned to only a limited number of days X and also can be assigned to days occuring on or after a particular number Y.
Input is in the given Format :
T
N
Score X Y (150 4 1 means Score 150 can be assigned to atmost 4 days on or after day 1)
For eg :
T = 10
N = 5
150 4 1
120 4 3
200 2 7
100 10 5
50 5 1
Note = 2 Scores can have same value . Each day can be assigned at most 1 score.
The optimum result for above example would be : 150 150 150 150 120 120 200 200 120 120.
What i tried :
I sorted the list according to the scores and started assigning the highest scores first.
In the above example I would start with 200 and assign it to 7 and 8 days.
Similarly I would assign the next highest score 150 to 1,2,3 and 4 days.
and so on ...
But this would take O(N * T) time. N for iterting over list of scores and T for checking and assigning scores over the time line(in the worst case).
The goal is to maximise and calculate the final score.
Is there a more elegant way to do this? Like without even assigning the scores and thus doing away with the T part of O(N * T).
I coded up a pretty straight forward implementation of your algorithm:
#include <vector>
#include <algorithm>
#include <array>
constexpr int T = 10;
struct Item {
int score;
int count;
int min;
};
std::array<Item, 5> input={{
{150, 4, 1},
{120, 4, 3},
{200, 2, 7},
{100, 10, 5},
{50, 5, 1}
}};
std::array<bool, T> days{};
int main() {
// preprocess input
std::sort(input.begin(), input.end(), [](auto l, auto r) {return l.score > r.score; });
int totalScore = 0;
int lastFreeDay = T - 1;
[&] {
for (auto spec : input) {
// scan forward to find open spots for the scores
for (int pos = spec.min-1; spec.count && pos < lastFreeDay; ++pos) {
if (!days[pos]) {
days[pos] = true;
totalScore += spec.score;
spec.count--;
}
}
// we weren't able to assign all scores of this entry,
// so every day after spec.min has already a score assigned to it.
// lets scan backward and see where the last free one is
if (spec.count > 0) {
lastFreeDay = spec.min;
while (days[lastFreeDay]) {
if (--lastFreeDay == -1) {
return;
}
}
}
}
}();
return totalScore;
}
I'm not sure what the exact algorithmic complexity is, but you can see two things:
At the beginning, there are very few collisions, so the inner loop doesn't actually depend on T, so it behaves more like O(N*k) (where k is the average number of times you can assign a particular score).
Even if N grows very large, not all scores can actually be processed, because the algorithm can terminate early and compares the latest free day against the earliest da a score can be assigned to.
Of course, you can create an worst case input, where you have T*(T+1)/2 passes of the inner loop (for N == T and k = 1 and min_i = 1) but my gut feeling is that on average it is much better than O(N*T) or at least has a very small constant (actually, the sort could be the dominant factor).
Long story short: I'm pretty confident that your algorithm is in fact applicable in practice and could probably be further improved by more intelligent data structures as suggested by Prune.
If you maintain a table of available intervals, I believe that you can keep this to O(N + T). Don't range through the entire length T each time; just check your list of open intervals and begin at the first available interval that contains the input line's Y value. There will be no more than N/2 intervals in this "open" list, and either hashing or a binary search can keep the complexity under control.

Divide and Conquer to find maximum difference in an array

I am trying to solve a problem where given an array I need to calculate the maximum difference such that the larger element appears after the smaller element.
Here is a better problem statement:
Given the stock prices on each day for n days, what is the maximum profit a person can make by doing exactly one transaction. One transaction means that the person can buy exactly one stock on one day and sell it on a later date.
I am trying to solve this problem using divide and conquer algo.
In my recursive function i am trying to spilt the array into two halves, but i am not sure on how to proceed with logic. Do i just get the max difference in each halves and compare?
int calculateMaxDiff(int *src, int start, int end){
if(end - start == 1) return src[start];
int middle = (start + end)/ 2;
int half1_diff;
int half2_diff;
half1_diff = calculateMaxDiff(src, start, middle);
half2_diff = calculateMaxDiff(src, middle, end);
//Do i need to have two loops here that calculate the diffs for each halves
....
return max(half1_diff, half2_diff);
}
Edit: Example output
Give an array {12, 9, 18, 3, 7, 11, 6, 15, 6, 1 ,10} should return 12 as a result of difference between 15 and 3
The question in your problem can be translated into a better problem statement:
Given the stock prices on each day for n days, what is the maximum profit a person can make by doing exactly one transaction. One transaction means that the person can buy exactly one stock on one day and sell it on a later date.
The divide-and-conquer solution: Let's see if we can solve this by splitting the input in half, solving the problem in each subarray, then combining the two together. Turns out we actually can do this, and can do so efficiently! The intuition is as follows. If we have a single day, the best option is to buy on that day and then sell it back on the same day for no profit. Otherwise, split the array into two halves. If we think about what the optimal answer might be, it must be in one of three places:
The correct buy/sell pair occurs completely within the first half.
The correct buy/sell pair occurs completely within the second half.
The correct buy/sell pair occurs across both halves - we buy in the first half, then sell in the second half.
We can get the values for (1) and (2) by recursively invoking our algorithm on the first and second halves. For option (3), the way to make the highest profit would be to buy at the lowest point in the first half and sell in the greatest point in the second half. We can find the minimum and maximum values in the two halves by just doing a simple linear scan over the input and finding the two values. This then gives us an algorithm with the following recurrence:
T(n) = 2T(n/2) + O(n)
T(n) = O(nlogn)
Here is a simple implementation in Python. Its very simple to understand and its also easy to convert to C++:
def DivideAndConquerSingleSellProfit(arr):
# Base case: If the array has zero or one elements in it, the maximum
# profit is 0.
if len(arr) <= 1:
return 0;
# Cut the array into two roughly equal pieces.
left = arr[ : len(arr) / 2]
right = arr[len(arr) / 2 : ]
# Find the values for buying and selling purely in the left or purely in
# the right.
leftBest = DivideAndConquerSingleSellProfit(left)
rightBest = DivideAndConquerSingleSellProfit(right)
# Compute the best profit for buying in the left and selling in the right.
crossBest = max(right) - min(left)
# Return the best of the three
return max(leftBest, rightBest, crossBest)
Edit: Here is the C++ implementation for the above algorithm
#include <iostream>
#include <algorithm>
using namespace std;
int calculateMin(int a[], int low, int high)
{
int i,mini;
mini = a[low];
for(i=low;i<=high;i++)
{
if(a[i]<mini)
{
mini = a[i];
}
}
return mini;
}
int calculateMax(int a[], int low, int high)
{
int i,maxi;
maxi = a[low];
for(i=low;i<=high;i++)
{
if(a[i]>maxi)
{
maxi = a[i];
}
}
return maxi;
}
int calculateMaxDiff(int a[], int low, int high)
{
if(low>=high)
return 0;
int mid = (low+high)/2;
int leftPartition = calculateMaxDiff(a,low,mid);
int rightPartition = calculateMaxDiff(a,mid+1,high);
int left = calculateMin(a,low,mid); // calculate the min value in the left partition
int right = calculateMax(a,mid+1,high); // calculate the max value in the right partition
return max(max(leftPartition, rightPartition), (right - left));
}
int main() {
int arr[] = {12, 9, 18, 3, 7, 11, 6, 15, 6, 1 ,10};
int len = sizeof(arr)/sizeof(arr[0]);
int ans = calculateMaxDiff(arr, 0, len-1);
cout << "Maximum Profit: " <<ans<<endl;
return 0;
}
Hope it helps!!!
There is no need in complicated D/C algorithm because simple cycle with checking like
maxdiff = max(current - min_so_far, maxdiff)
update min_so_far
solves the problem
If you really want to apply divide and conquer method, you may return triplet {local_min, local_max, local_max_diff} from recursive function like:
left = calculateMaxDiff(start, middle)
right = calculateMaxDiff(middle + 1, end)
return {min(left.local_min, right.local_min),
max(left.local_max, right.local_max),
max(left.local_diff, right.local_diff, right.localmax - left.local_min)
The key for a divide and conquer algorithm is the conquer part.
For this problem the most important condition is:
the larger element appears after the smaller element
For an array src, after dividing src to 2 halves, half1 and half2, suppose the answer would be in position i and j, there are 3 cases now:
i and j are both in half1 -> half1_diff
i and j are both in half2 -> half2_diff
i is in half1 and j is in half2
So the main part is to deal with case3. As the larger one comes after, so we just need to find the minimum value min_half1 in half1 and the maximum value max_half2 in half2, and check if it meets the condition max_half2 >= min_half1 and update the result as max(half1_diff, half2_diff, max_half2-min_half1).
In order to calculate min_half1 and max_half2 efficiently, you have to keep the record of min and max value of the array, and it takes O(1) time.
So T(n) = 2T(n/2) + O(1), T(n) = O(n).
Check the example for more details
http://ideone.com/TbIL2r

Is Coin Change Algorithm That Output All Combinations Still Solvable By DP?

For example, total amount should be 5 and I have coins with values of 1 and 2. Then there are 3 ways of combinations:
1 1 1 1 1
1 1 1 2
1 2 2
I've seen some posts about how to calculate total number of combinations with dynamic programming or with recursion, but I want to output all the combinations like my example above. I've come up with a recursive solution below.
It's basically a backtracking algorithm, I start with the smallest coins first and try to get to the total amount, then I remove some coins and try using second smallest coins ... You can run my code below in http://cpp.sh/
The total amount is 10 and the available coin values are 1, 2, 5 in my code.
#include <iostream>
#include <stdlib.h>
#include <iomanip>
#include <cmath>
#include <vector>
using namespace std;
vector<vector<int>> res;
vector<int> values;
int total = 0;
void helper(vector<int>& curCoins, int current, int i){
int old = current;
if(i==values.size())
return;
int val = values[i];
while(current<total){
current += val;
curCoins.push_back(val);
}
if(current==total){
res.push_back(curCoins);
}
while (current>old) {
current -= val;
curCoins.pop_back();
if (current>=0) {
helper(curCoins, current, i+1);
}
}
}
int main(int argc, const char * argv[]) {
total = 10;
values = {1,2,5};
vector<int> chosenCoins;
helper(chosenCoins, 0, 0);
cout<<"number of combinations: "<<res.size()<<endl;
for (int i=0; i<res.size(); i++) {
for (int j=0; j<res[i].size(); j++) {
if(j!=0)
cout<<" ";
cout<<res[i][j];
}
cout<<endl;
}
return 0;
}
Is there a better solution to output all the combinations for this problem? Dynamic programming?
EDIT:
My question is is this problem solvable using dynamic programming?
Thanks for the help. I've implemented the DP version here: Coin Change DP Algorithm Print All Combinations
A DP solution:
We have
{solutions(n)} = Union ({solutions(n - 1) + coin1},
{solutions(n - 2) + coin2},
{solutions(n - 5) + coin5})
So in code:
using combi_set = std::set<std::array<int, 3u>>;
void append(combi_set& res, const combi_set& prev, const std::array<int, 3u>& values)
{
for (const auto& p : prev) {
res.insert({{{p[0] + values[0], p[1] + values[1], p[2] + values[2]}}});
}
}
combi_set computeCombi(int total)
{
std::vector<combi_set> combis(total + 1);
combis[0].insert({{{0, 0, 0}}});
for (int i = 1; i <= total; ++i) {
append(combis[i], combis[i - 1], {{1, 0, 0}});
if (i - 2 >= 0) { append(combis[i], combis[i - 2], {{0, 1, 0}}); }
if (i - 5 >= 0) { append(combis[i], combis[i - 5], {{0, 0, 1}}); }
}
return combis[total];
}
Live Demo.
Exhaustive search is unlikely to be 'better' with dynamic programming, but here's a possible solution:
Start with a 2d array of combination strings, arr[value][index] where value is the total worth of the coins. Let X be target value;
starting from arr[0][0] = "";
for each coin denomination n, from i = 0 to X-n you copy all the strings from arr[i] to arr[i+n] and append n to each of the strings.
for example with n=5 you would end up with
arr[0][0] = "", arr[5][0] = "5" and arr[10][0] = "5 5"
Hope that made sense. Typical DP would just count instead of having strings (you can also replace the strings with int vector to keep count instead)
Assume that you have K the total size of the output your are expecting (the total number of coins in all the combinations). Obviously you can not have a solution that runs faster than O(K), if you actually need to output all them. As K can be very large, this will be a very long running time, and in the worst case you will get little profit from the dynamic programming.
However, you still can do better than your straightforward recursive solution. Namely, you can have a solution running in O(N*S+K), where N is the number of coins you have and S is the total sum. This will not be better than straightforward solution for the worst possible K, but if K is not so big, you will get it running faster than your recursive solution.
This O(N*S+K) solution can be relatively simply coded. First you run the standard DP solution to find out for each sum current and each i whether the sum current can be composed of first i coin types. You do not yet calculate all the solutions, you just find out whether at least one solution exists for each current and i. Then, you write a recursive function similar to what you have already written, but before you try each combination, you check using you DP table whether it is worth trying, that is, whether at least one solution exists. Something like:
void helper(vector<int>& curCoins, int current, int i){
if (!solutionExists[current, i]) return;
// then your code goes
this way each branch of the recursion tree will finish in finding a solution, and therefore the total recursion tree size will be O(K), and the total running time will be O(N*S+K).
Note also that all this is worth only if you really need to output all the combinations. If you need to do something else with the combinations you get, it is very probable that you do not actually need all the combinations and you may adapt the DP solution for that. For example, if you want to print only m-th of all solutions, this can be done in O(N*S).
You just need to make two passes over the data structure (a hash table will work well as long as you've got a relatively small number of coins).
The first one finds all unique sums less than the desired total (actually you could stop perhaps at 1/2 the desired total) and records the simplest way (least additions required) to obtain that sum. This is essentially the same as the DP.
The second pass then goes starts at the desired total and works its way backwards through the data to output all ways that the total can be generated.
This ends up being a two stage approach of what Petr is suggesting.
The actual amount of non distinct valid combinations for amounts {1, 2, 5} and N = 10 is 128, using a pure recursive exhaustive technique (Code below). My question is can an exhaustive search be improved with memoization/dynamic programming. If so, how can I modify the algorithm below to incorporate such techniques.
public class Recursive {
static int[] combo = new int[100];
public static void main(String argv[]) {
int n = 10;
int[] amounts = {1, 2, 5};
ways(n, amounts, combo, 0, 0, 0);
}
public static void ways(int n, int[] amounts, int[] combo, int startIndex, int sum, int index) {
if(sum == n) {
printArray(combo, index);
}
if(sum > n) {
return;
}
for(int i=0;i<amounts.length;i++) {
sum = sum + amounts[i];
combo[index] = amounts[i];
ways(n, amounts, combo, startIndex, sum, index + 1);
sum = sum - amounts[i];
}
}
public static void printArray(int[] combo, int index) {
for(int i=0;i < index; i++) {
System.out.print(combo[i] + " ");
}
System.out.println();
}
}

Algorithm to determine coin combinations

I was recently faced with a prompt for a programming algorithm that I had no idea what to do for. I've never really written an algorithm before, so I'm kind of a newb at this.
The problem said to write a program to determine all of the possible coin combinations for a cashier to give back as change based on coin values and number of coins. For example, there could be a currency with 4 coins: a 2 cent, 6 cent, 10 cent and 15 cent coins. How many combinations of this that equal 50 cents are there?
The language I'm using is C++, although that doesn't really matter too much.
edit: This is a more specific programming question, but how would I analyze a string in C++ to get the coin values? They were given in a text document like
4 2 6 10 15 50
(where the numbers in this case correspond to the example I gave)
This problem is well known as coin change problem. Please check this and this for details. Also if you Google "coin change" or "dynamic programming coin change" then you will get many other useful resources.
Here's a recursive solution in Java:
// Usage: int[] denoms = new int[] { 1, 2, 5, 10, 20, 50, 100, 200 };
// System.out.println(ways(denoms, denoms.length, 200));
public static int ways(int denoms[], int index, int capacity) {
if (capacity == 0) return 1;
if (capacity < 0 || index <= 0 ) return 0;
int withoutItem = ways(denoms, index - 1, capacity);
int withItem = ways(denoms, index, capacity - denoms[index - 1]);
return withoutItem + withItem;
}
This seems somewhat like a Partition, except that you don't use all integers in 1:50. It also seems similar to bin packing problem with slight differences:
Wikipedia: Partition (Number Theory)
Wikipedia: Bin packing problem
Wolfram Mathworld: Partiton
Actually, after thinking about it, it's an ILP, and thus NP-hard.
I'd suggest some dynamic programming appyroach. Basically, you'd define a value "remainder" and set it to whatever your goal was (say, 50). Then, at every step, you'd do the following:
Figure out what the largest coin that can fit within the remainder
Consider what would happen if you (A) included that coin or (B) did not include that coin.
For each scenario, recurse.
So if remainder was 50 and the largest coins were worth 25 and 10, you'd branch into two scenarios:
1. Remainder = 25, Coinset = 1x25
2. Remainder = 50, Coinset = 0x25
The next step (for each branch) might look like:
1-1. Remainder = 0, Coinset = 2x25 <-- Note: Remainder=0 => Logged
1-2. Remainder = 25, Coinset = 1x25
2-1. Remainder = 40, Coinset = 0x25, 1x10
2-2. Remainder = 50, Coinset = 0x25, 0x10
Each branch would split into two branches unless:
the remainder was 0 (in which case you would log it)
the remainder was less than the smallest coin (in which case you would discard it)
there were no more coins left (in which case you would discard it since remainder != 0)
If you have 15, 10, 6 and 2 cents coins and you need to find how many distinct ways are there to arrive to 50 you can
count how many distinct ways you have to reach 50 using only 10, 6 and 2
count how many distinct ways you have to reach 50-15 using only 10, 6 and 2
count how many distinct ways you have to reach 50-15*2 using only 10, 6 and 2
count how many distinct ways you have to reach 50-15*3 using only 10, 6 and 2
Sum up all these results that are of course distinct (in the first I used no 15c coins, in the second I used one, in the third two and in the fourth three).
So you basically can split the problem in smaller problems (possibly smaller amount and fewer coins). When you have just one coin type the answer is of course trivial (either you cannot reach the prescribed amount exactly or you can in the only possible way).
Moreover you can also avoid repeating the same computation by using memoization, for example the number of ways of reach 20 using only [6, 2] doesn't depend if the already paid 30 have been reached using 15+15 or 10+10+10, so the result of the smaller problem (20, [6, 2]) can
be stored and reused.
In Python the implementation of this idea is the following
cache = {}
def howmany(amount, coins):
prob = tuple([amount] + coins) # Problem signature
if prob in cache:
return cache[prob] # We computed this before
if amount == 0:
return 1 # It's always possible to give an exact change of 0 cents
if len(coins) == 1:
if amount % coins[0] == 0:
return 1 # We can match prescribed amount with this coin
else:
return 0 # It's impossible
total = 0
n = 0
while n * coins[0] <= amount:
total += howmany(amount - n * coins[0], coins[1:])
n += 1
cache[prob] = total # Store in cache to avoid repeating this computation
return total
print howmany(50, [15, 10, 6, 2])
As for the second part of your question, suppose you have that string in the file coins.txt:
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::ifstream coins_file("coins.txt");
std::vector<int> coins;
std::copy(std::istream_iterator<int>(coins_file),
std::istream_iterator<int>(),
std::back_inserter(coins));
}
Now the vector coins will contain the possible coin values.
For such a small number of coins you can write a simple brute force solution.
Something like this:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> v;
int solve(int total, int * coins, int lastI)
{
if (total == 50)
{
for (int i = 0; i < v.size(); i++)
{
cout << v.at(i) << ' ';
}
cout << "\n";
return 1;
}
if (total > 50) return 0;
int sum = 0;
for (int i = lastI; i < 6; i++)
{
v.push_back(coins[i]);
sum += solve(total + coins[i], coins, i);
v.pop_back();
}
return sum;
}
int main()
{
int coins[6] = {2, 4, 6, 10, 15, 50};
cout << solve(0, coins, 0) << endl;
}
A very dirty brute force solution that prints all possible combinations.
This is a very famous problem, so try reading about better solutions others have provided.
One rather dumb approach is the following. You build a mapping "coin with value X is used Y times" and then enumerate all possible combinations and only select those which total the desired sum. Obviously for each value X you have to check Y ranging from 0 up to the desired sum. This will be rather slow, but will solve your task.
It's very similar to the knapsack problem
You basically have to solve the following equation: 50 = a*4 + b*6 + c*10 + d*15, where the unknowns are a,b,c,d. You can compute for instance d = (50 - a*4 - b*6 - c*10)/15 and so on for each variable. Then, you start giving d all the possible values (you should start with the one that has the least possible values, here d): 0,1,2,3,4 and than start giving c all the possible values depending on the current value of d and so on.
Sort the List backwards: [15 10 6 4 2]
Now a solution for 50 ct can contain 15 ct or not.
So the number of solutions is the number of solutions for 50 ct using [10 6 4 2] (no longer considering 15 ct coins) plus the number of solutions for 35 ct (=50ct - 15ct) using [15 10 6 4 2]. Repeat the process for both sub-problems.
An algorithm is a procedure for solving a problem, it doesn't have to be in any particular language.
First work out the inputs:
typedef int CoinValue;
set<CoinValue> coinTypes;
int value;
and the outputs:
set< map<CoinValue, int> > results;
Solve for the simplest case you can think of first:
coinTypes = { 1 }; // only one type of coin worth 1 cent
value = 51;
the result should be:
results = { [1 : 51] }; // only one solution, 51 - 1 cent coins
How would you solve the above?
How about this:
coinTypes = { 2 };
value = 51;
results = { }; // there is no solution
what about this?
coinTypes = { 1, 2 };
value = { 4 };
results = { [2: 2], [2: 1, 1: 2], [1: 4] }; // the order I put the solutions in is a hint to how to do the algorithm.
Recursive solution based on algorithmist.com resource in Scala:
def countChange(money: Int, coins: List[Int]): Int = {
if (money < 0 || coins.isEmpty) 0
else if (money == 0) 1
else countChange(money, coins.tail) + countChange(money - coins.head, coins)
}
Another Python version:
def change(coins, money):
return (
change(coins[:-1], money) +
change(coins, money - coins[-1])
if money > 0 and coins
else money == 0
)