Dynamic programming :how to solve all combination ordered coin change problem for large input - algorithm

I have a challenge to find number of ways to get a sum of a given number from an array containing coins. For example:
coins: {2,3,5,7}
sum: 8
total ways: 6 -> (2 + 2 + 2 + 2), (2 + 3 + 3), (3 + 2 + 3), (3 + 3 + 2), (3 + 5), and (5 + 3).
I have the solution that works using dp pseudo code:
build an array ar of size "sum"
ar[0]=1
for i = 1 to sum do:
ar[i]=ar[i-2]+ar[i-3]+ar[i-5]+ar[i-7]
return ar[sum]
As mentioned this code works fine, but the platform I am running this in can have sum as large as 1019, and as expected it gives me a timeout. Is there any other way this can be dealt with? I have even tried to reduce the size of the array when it goes beyond size i-largest value in coins. But that as well times out.

Related

Simple algorithm for a simple balancing problem

I have three buckets. They do not contain the same amount of water and they can contain up to 50 liters each.
Now I want to add more water to the buckets. This amount may vary from time to time, and might also be more than 50 x 3 liters. My goal is to fill the buckets with the new water so they have about an equal amount in each of the buckets - as close to equal as possible, but it's not a criterion. And also without exceeding the upper limit of 50.
Is there a simple and easy-to-read algorithm that would balance (as much as possible) the amount of water in the buckets?
I always know how much water there already is in each bucket.
I always know how much new water I get.
Water already in buckets cannot be touched
Equal water level is not a criterion, but further from the limits is desirable
Yes, there is a simple algorithm as follows:
Sort the buckets by the amount of water. Let's call them a, b, c sorted none-decreasing.
The total amount of water that you need to balance them is (c - b) + (c - a) = 2*c - b - a. Let's call the needed amount t.
If the available water is less than t, it is not possible to balance the buckets.
Otherwise, add c - b to b and c - a to a.
Update based on the new contraints in the edit:
If you have enough water to bring the amount of water in the lesser filled buckets to the level of the more full bucket, the previous algorithm works just fine.
But in case there isn't enough water available to make all three equal (note that this can be calculated up front as described above), first fill the bucket with the smallest amount of water up until it is equal to the middle one. Then divide the remaining amount of available water and distribute it equally between the two buckets that are equal but have less water than the other.
The intuition is this: When you add to the smallest bucket up until you reach the middle one, you are decreasing the absolute difference between the three by 2 for each added liter. That's because the smallest is approaching the middle and the largest one.
Example:
a, b, c = 5, 3, 1
available_water = 4
difference = (5 - 3) + (5 - 1) + (3 - 1) = 8
add 2 to the smallest:
a, b, c = 5, 3, 3
available_water = 2
difference = (5 - 3) + (5 - 3) + (3 - 3) = 4
Note that we reduced the difference by 2 times the amount of used water
add 1 to each of the smaller buckets:
a, b, c = 5, 4, 4
available_water = 0
difference = (5 - 4) + (5 - 4) = 2
Now if we didn't follow this algorithm and just arbitrary used the water:
add 2 to the middle bucket:
a, b, c = 5, 5, 1
available_water = 2
difference = (5 - 5) + (5 - 1) + (5 - 1) = 8
add 2 to the smallest one:
a, b, c = 5, 5, 3
available_water = 0
difference = (5 - 5) + (5 - 3) + (5 - 3) = 4

Count the total number ways to reach the nth stair using step 1, 2 or 3 but the step 3 can be taken only once

For any given value N we have to find the number of ways to reach the top while using steps of 1,2 or 3 but we can use 3 steps only once.
for example if n=7
then possible ways could be
[1,1,1,1,1,1,1]
[1,1,1,1,1,2]
etc but we cannot have [3,3,1] or [1,3,3]
I have managed to solve the general case without the constraint of using 3 only once with dynamic programming as it forms a sort of fibonacci series
def countWays(n) :
res = [0] * (n + 1)
res[0] = 1
res[1] = 1
res[2] = 2
for i in range(3, n + 1) :
res[i] = res[i - 1] + res[i - 2] + res[i - 3]
return res[n]
how do I figure out the rest of it?
Let res0[n] be the number of ways to reach n steps without using a 3-step, and let res1[n] be the number of ways to reach n steps after having used a 3-step.
res0[i] and res1[i] are easily calculated from the previous values, in a manner similar to your existing code.
This is an example of a pretty common technique that is often called "graph layering". See, for example: Shortest path in a maze with health loss
Let us first ignore the three steps here. Imagine that we can only use steps of one and two. Then that means that for a given number n. We know that we can solve this with n steps of 1 (one solution), or n-2 steps of 1 and one step of 2 (n-1 solutions); or with n-4 steps of 1 and two steps of 2, which has n-2×n-3/2 solutions, and so on.
The number of ways to do that is related to the Fibonacci sequence. It is clear that the number of ways to construct 0 is one: just the empty list []. It is furthermore clear that the number of ways to construct 1 is one as well: a list [1]. Now we can proof that the number of ways Wn to construct n is the sum of the ways Wn-1 to construct n-1 plus the number of ways Wn-2 to construct n-2. The proof is that we can add a one at the end for each way to construct n-1, and we can add 2 at the end to construct n-2. There are no other options, since otherwise we would introduce duplicates.
The number of ways Wn is thus the same as the Fibonacci number Fn+1 of n+1. We can thus implement a Fibonacci function with caching like:
cache = [0, 1, 1, 2]
def fib(n):
for i in range(len(cache), n+1):
cache.append(cache[i-2] + cache[i-1])
return cache[n]
So now how can we fix this for a given step of three? We can here use a divide and conquer method. We know that if we use a step of three, it means that we have:
1 2 1 … 1 2 3 2 1 2 2 1 2 … 1
\____ ____/ \_______ _____/
v v
sum is m sum is n-m-3
So we can iterate over m, and each time multiply the number of ways to construct the left part (fib(m+1)) and the right part (fib(n-m-3+1)) we here can range with m from 0 to n-3 (both inclusive):
def count_ways(n):
total = 0
for m in range(0, n-2):
total += fib(m+1) * fib(n-m-2)
return total + fib(n+1)
or more compact:
def count_ways(n):
return fib(n+1) + sum(fib(m+1) * fib(n-m-2) for m in range(0, n-2))
This gives us:
>>> count_ways(0) # ()
1
>>> count_ways(1) # (1)
1
>>> count_ways(2) # (2) (1 1)
2
>>> count_ways(3) # (3) (2 1) (1 2) (1 1 1)
4
>>> count_ways(4) # (3 1) (1 3) (2 2) (2 1 1) (1 2 1) (1 1 2) (1 1 1 1)
7

Finding number representation in different bases

I was recently solving a problem when I encountered this one: APAC Round E Q2
Basically the question asks to find the smallest base (>1) in which if the number (input) is written then the number would only consist of 1s. Like 3 if represented in base 2 would become 1 (consisting of only 1s).
Now, I tried to solve this the brute force way trying out all bases from 2 till the number to find such a base. But the constraints required a more efficient one.
Can anyone provide some help on how to approach this?
Here is one suggestion: A number x that can be represented as all 1s in a base b can be written as x = b^n + b^(n-1) + b^(n-2) + ... + b^1 + 1
If you subtract 1 from this number you end up with a number divisble by b:
b^n + b^(n-1) + b^(n-2) + ... + b^1 which has the representation 111...110. Dividing by b means shifting it right once so the resulting number is now b^(n-1) + b^(n-2) + ... + b^1 or 111...111 with one digit less than before. Now you can repeat the process until you reach 0.
For example 13 which is 111 in base 3:
13 - 1 = 12 --> 110
12 / 3 = 4 --> 11
4 - 1 = 3 --> 10
3 / 3 = 1 --> 1
1 - 1 = 0 --> 0
Done => 13 can be represented as all 1s in base 3
So in order to check if a given number can be written with all 1s in a base b you can check if that number is divisble by b after subtracting 1. If not you can immediately start with the next base.
This is also pretty brute-forcey but it doesn't do any base conversions, only one subtraction, one divisions and one mod operation per iteration.
We can solve this in O( (log2 n)^2 ) complexity by recognizing that the highest power attainable in the sequence would correspond with the smallest base, 2, and using the formula for geometric sum:
1 + r + r^2 + r^3 ... + r^(n-1) = (1 - r^n) / (1 - r)
Renaming the variables, we get:
n = (1 - base^power) / (1 - base)
Now we only need to check power's from (floor(log2 n) + 1) down to 2, and for each given power, use a binary search for the base. For example:
n = 13:
p = floor(log2 13) + 1 = 4:
Binary search for base:
(1 - 13^4) / (1 - 13) = 2380
...
No match for power = 4.
Try power = 3:
(1 - 13^3) / (1 - 13) = 183
(1 - 6^3) / (1 - 6) = 43
(1 - 3^3) / (1 - 3) = 13 # match
For n around 10^18 we may need up to (floor(log2 (10^18)) + 1)^2 = 3600 iterations.

How to iterate through array combinations with constant sum efficiently?

I have an array and its length is X. Each element of the array has range 1 .. L. I want to iterate efficiently through all array combinations that has sum L.
Correct solutions for: L = 4 and X = 2
1 3
3 1
2 2
Correct solutions for: L = 5 and X = 3
1 1 3
1 3 1
3 1 1
1 2 2
2 1 2
2 2 1
The naive implementation is (no wonder) too slow for my problem (X is up to 8 in my case and L is up to 128).
Could anybody tell me how is this problem called or where to find a fast algorithm for the problem?
Thanks!
If I understand correctly, you're given two numbers 1 ≤ X ≤ L and you want to generate all sequences of positive integers of length X that sum to L.
(Note: this is similar to the integer partition problem, but not the same, because you consider 1,2,2 to be a different sequence from 2,1,2, whereas in the integer partition problem we ignore the order, so that these are considered to be the same partition.)
The sequences that you are looking for correspond to the combinations of X − 1 items out of L − 1. For, if we put the numbers 1 to L − 1 in order, and pick X − 1 of them, then the lengths of intervals between the chosen numbers are positive integers that sum to L.
For example, suppose that L is 16 and X is 5. Then choose 4 numbers from 1 to 15 inclusive:
Add 0 at the beginning and 16 at the end, and the intervals are:
and 3 + 4 + 1 + 6 + 2 = 16 as required.
So generate the combinations of X − 1 items out of L − 1, and for each one, convert it to a partition by finding the intervals. For example, in Python you could write:
from itertools import combinations
def partitions(n, t):
"""
Generate the sequences of `n` positive integers that sum to `t`.
"""
assert(1 <= n <= t)
def intervals(c):
last = 0
for i in c:
yield i - last
last = i
yield t - last
for c in combinations(range(1, t), n - 1):
yield tuple(intervals(c))
>>> list(partitions(2, 4))
[(1, 3), (2, 2), (3, 1)]
>>> list(partitions(3, 5))
[(1, 1, 3), (1, 2, 2), (1, 3, 1), (2, 1, 2), (2, 2, 1), (3, 1, 1)]
There are (L − 1)! / (X − 1)!(L − X)! combinations of X − 1 items out of L − 1, so the runtime of this algorithm (and the size of its output) is exponential in L. However, if you don't count the output, it only needs O(L) space.
With L = 128 and X = 8, there are 89,356,415,775 partitions, so it'll take a while to output them all!
(Maybe if you explain why you are computing these partitions, we might be able to suggest some way of meeting your requirements without having to actually produce them all.)

number of ways of distribution

if we have n different things and we need to distribute them among m different people then how many ways can we do it such that for each of the m persons there is conditions that:
person 1 can have at least a things and at most b things
person 2 can have at least c things and at most d things
.. and so on ?
e.g if n = 5 and m =3 and the conditions are:
person 1 can receive at least 0 and at most 1 gift
person 2 can receive at least 1 and at most 3 gift
person 3 can receive at least 1 and at most 4 gift
then the number of ways of distributing these 5 gifts is 6((0 1 4), (0 2 3), (0 3 2), (1 1 3), (1 2 2), (1 3 1)).
One way i believe is to iterate through all possible combinations for each range and see which ones sum upto n , but can't think of an efficient algorithm.
Thanks
You probably want to use a generating function approach. Represent the number of objects that person i gets by the exponents of x. This means that if person i can have at least 3 and at most 7 things, this corresponds to the term
x^3 + x^4 + x^5 + x^6 + x^7
Remember to think of + as OR and * as AND. If we want to impose conditions and person 1 and person 2, then multiply their functions together. For example, with person 1 having between 3 and 7 things, and say person 2 has at least 5 things, and add a third person with at most 10 things. Then we get:
(x^3 + x^4 + x^5 + x^6 + x^7) * (x^5 + x^6 + ... ) * (1 + x + x^2 + ... + x^10)
which can also be written as
(x^3 + x^4 + x^5 + x^6 + x^7) * ( x^5/(1+x) ) * (1 + x + x^2 + ... + x^10)
The way to get information back from this is the following. The coefficient of x^M in the expansion of these terms gives the number of ways to distribute a total of M things among all the people subject to the given constraints.
You can work this out from the formulas, or write a program to extract the coefficient, but the idea is to use generating functions as a convenient and efficient way to encode the constraints along with the answer.

Resources