Recursive Solution for Rod Cutting problem - dynamic programming - algorithm

Problem Statement: Given a rod of length n inches and an array of
prices that includes prices of all pieces of size smaller than n.
Determine the maximum value obtainable by cutting up the rod and
selling the pieces.
For this problem, I am confused as to why everywhere I see the solution to this problem i.e. the maximum value of the Rod defined as
R[n] = Max (p[n], R[n-1] + P[1], R[n-2] + P[2] + ... P[1] + R[n-1] --- 1
and not as
R[n] = Max (p[n], R[n-1] + R[1], R[n-2] + R[2] + ... R[1] + R[n-1] --- 2
where R[n] means the maximum revenue that we can get by selling n rods.
Base case as:
R[0] = some value
R[1] = somevalue
The eq 2 is more correct and apt because at no point R[i] will ever be less than P[i].
What am I missing?

Both equations give the same answer. In that sense none of them is more correct than the other. It is a matter of taste which one you prefer. I found eq 1 a bit more intuitive. The solution is the maximum of taking the whole rod, or cutting off a piece of length 1 and do the best with the rest, or cutting off a piece of length 2 and do the best with the rest, ...

Related

confusion about rod cutting algorithm - dynamic programming

I recently saw a rod cutting problem, where B(i) = optimal price for cutting a rod of length i units and p(i) = price of a rod of length i units.
The algorithm given is something like this:
B(i) = max(1<=k<=i) {p(k) + B(i-k)}
Shouldn't it be something like this:
B(i) = max(1<=k<=floor(i/2)) {B(k) + B(i-k)}
where B(1) = p(1);
so that both parts 've the optimal cost instead of cost for a single rod for one part and optimal cost for the second part.
for example: B(4) = max{ (B(1) + B(3)); (B(2) + B(2)) }
instead of max{ (p(1) + B(3)); (p(2) + B(2)); (p(3) + B(1)) }
Can someone please explain this?
Actually the formula is correct. You have B(i) = max(1<=k<=i) {p(k) + B(i-k)}. Let's assume you have a rope of length i. If you are to cut it then you will cut a piece of length k where k is between 1 and i and will go on cutting the remaining part of the rope. So overall it costs you p(k)(price to cut the initial part that you decided you will not cut anymore) and the price to cut the remaining B(i-k). This is precisely what the formula does.
Your solution will also do the job but it has a slight drawback - the solution for each subproblem depends on the solution of two(instead of one) simpler subproblems. I believe because of that it will perform worse on the average. Of course having a subproblem depend on several simpler problems is not forbidden or wrong.
Let us assume that the optimal price of the rod of length i will be obtained by cutting the rod into p parts of length l1, l2, .., lp such that i= l1+ l2 +..+ lp and l1<l2<l3<…<lp (for simplicity).
There exists a rod piece of length l1 in the optimal solution means that if the rod piece of length l1 is further broken into smaller pieces, then the price of the rod piece of length l1 will decrease. Hence for a rod piece of length l1, we can say that b[l1] = p[l1]. Similarly we have established, b[l2] = p[l2], b[l3]= p[l3], ….., b[lp]= p[lp]. => b(i) = b(l1) + b(l2) +..+ b(lp) is optimal………………..Condition 1
Now consider the case of rod of length l1+l2. The claim is b(l1+l2) = b(l1) + b(l2) is optimal. Let us assume it is not the case. There exists an L such that b(l1+l2) = b(L) + b(l1+l2-L) is optimal. It means that there exists rods of length L and (l1+l2-L) such that:
b(L) + b(l1+l2-L)>b(l1)+b(l2).
=> b(l1) + b(l2) + b(l3) +..+ b(lp) < b(L) + b(l1+l2-L) +b(l3) +…+ b(lp).
=> Which is a contradiction { See Condition 1}
=> b(l1+l2) = b(l1) + b(l2) is optimal
=> Similarly b(l2+l3+l4) = b(l2) + b(l3) + b(l4) is optimal and so on.
Now we have a recurrence b(i) = b(k) + b(i-k) for 1<=k<i.
For k=l1, b(i) = b(l1) + b(i-l1) = p[l1] + b(i-l1).
For k=l1+l2, b(i) = b(l1+l2) + b(i-l1-l2)
= b(l1+l2) + b(l3 + l4 +…+lp)
= [b(l1) + b(l2)] + b(l3 + l4 +…+lp)
= b(l1) + [b(l2) + b(l3 + l4 +…+lp)]
= b(l1) + b(l2+l3+l4+…+lp)
= b(l1) + b(i-l1)
= p[l1] + b(i-l1)
Or for k= l1+l2, b(i) = p[k’] + b(i-k’) where k’=l1.
So to conclude, if we want to find optimal solution of a rod of length i, we try to break the rod of length i into 2 parts of length (l1+l2) and (i-l1+l2) and then we recursively find optimal solutions of the two rod pieces, we end up finding an optimal rod piece of length l1 and optimal solution of rod of length i-l1. Thus we can say:
b(i) = b(k) + b(i-k ) = p[k’] + b(i-k’) for 1<=k,k’<i.
The formula is correct. I think the confusion arises when we think of both formulas to be replacement of the other.
Though they count the same phenomena, it is done in two different ways:
Let, B(i) = optimal price for cutting a rod of length i units and
p(i) = price of a rod of length i units.
Formula 1: B(i) = max(1<=k<=floor(i/2)) {B(k) + B(i-k)} and P(i)
Formula 2: B(i) = max(1<=k<=i) {p(k) + B(i-k)})
Consider a rod of length 4,
it can be cut in the following ways :
1) uncut of length 4
2) 3, 1
3) 2, 2
4) 2, 1, 1
5) 1, 3
6) 1, 2, 1
7) 1, 1, 2
8) 1, 1, 1, 1
According to Formula 1:
option 1 corresponds to P(4)
option 2,5,6,7,8 corresponds to B(1) + B(3)
option 3,4,6,7,8 corresponds to B(2) + B(2)
According to Formula 2:
option 1 corresponds to P(4)
option 2 corresponds to P(3) + B(1)
option 3,4 corresponds to P(2) + B(2)
option 5,6,7,8 corresponds to P(1) + B(3)
So to conclude, 1 and 2 are counting the optimal solution but in different ways, where 2 is more compact and makes lesser recursive calls compared to 1.

Max subset of arrays whose mean is larger than threshold

I recently came across the following problem, and so far got no insight on how to solve it.
Let S = {v1, v2, v3, ..., vn} be a set of n arrays defined on the ℝ6. That is, each array has 6 entries.
For a given set of arrays, let the mean of a dimension be the average between the coordinates corresponding to that dimension for all elements in the set.
Also, let us define a certain property P of a set of arrays as the lowest value amongst all means of a set (there is a total of 6 means, one for each dimension). For instance, if a certain set has {10, 4, 1, 5, 6, 3} as means for its dimensions, then P for this set is 1.
Now to the definition of the problem: Return the maximum cardinality amongst all the subsets S' of S such that P(S') ≥ T, T a known threshold value, or 0 if such subset does not exist. Additionally, output any maximal S' (such that P(S') ≥ T).
Summarising: Inputs: the set S and the threshold value T. Output: A certain subset S' (|S'| is evidently immediate).
I first began trying to come up with a greedy solution, but got no success. Then, I moved on to a dynamic programming approach, but could not establish a recursion that solved the problem. I could expand a little more on my thoughts on the solution, but I don't think they would be of much use, given how far I got (or didn't get).
Any help would be greatly appreciated!
Bruteforce evaluation through recursion would have a time complexity of O(2^n) because each array can either be present in the subset or not.
One (still inefficient but slightly better) way to solve this problem is by taking the help of Integer Linear Programming.
Define Xi = { 1 if array Vi is present in the maximal subset, 0 otherwise }
Hence Cardinality k = summation(Xi) {i = 1 to n }
Also, since the average of all dimensions >= T, this means:
d11X1 + d12X2 + ... + d1nXn >= T*k
d21X1 + d22X2 + ... + d2nXn >= T*k
d31X1 + d32X2 + ... + d3nXn >= T*k
d41X1 + d42X2 + ... + d4nXn >= T*k
d51X1 + d52X2 + ... + d5nXn >= T*k
d61X1 + d62X2 + ... + d6nXn >= T*k
Objective function: Maximize( k )
Actually you should eliminate k by the cardinality equation but I have included it here for clarity.

SPOJ : Weighted Sum

You are given N integers, A[1] to A[N]. You have to assign weights to these integers such that their weighted sum is maximized. The weights should satisfy the following conditions :
Each weight should be an positive integer.
W[1] = 1
W[i] should be in the range [2, W[i-1] + 1] for i > 1
Weighted sum is defined as S = A[1] * W[1] + A[2] * W[2] + ... + A[N] * W[N]
eg :
n=4 , array[]={ 1 2 3 -4 } , answer = 6 when we assign { 1 2 3 2 } respective weights .
So, as far as my understanding and research , no Greed solution is possible for it . I worked out many testcases on pen n paper , but couldn't get a greedy strategy .
Any ideas/hints/approaches people .
Let dp[i][j] equal the maximum weighted sum we can make from A[1..i] by assigning weight j to A[i]. Clearly dp[i][j] = j*A[i] + max(dp[i - 1][(j - 1)..N]). There are O(N^2) states and our recurrence takes O(N) for each state so the overall time complexity will be O(N^3). To reduce it to O(N^2) we can notice that there is significant overlap in our recurrence.
If dp[i][j] = j * A[i] + max(dp[i - 1][(j - 1)..N]), then
dp[i][j - 1] = (j - 1)*A[i] + max(dp[i - 1][(j - 2)..N]) = (j - 1)*A[i] + max(dp[i - 1][j - 2], dp[i - 1][(j - 1)..N]) = (j - 1)*A[i] + max(dp[i - 1][j - 2], dp[i][j] - j*A[i])
Which means the recurrence takes only O(1) to compute, giving you O(N^2) time overall.
Fairly standard dynamic-programming methods can be used to solve this problem in O(N³) time. Let V(k,u) denote the best value that can be gotten using elements k...N when Wₖ₋₁ has the value u. Observe that V(k,u) is the maximum value of g·Aₖ+V(k-1,g) as g ranges from 2 to u+1, and that V(N,u) is (u+1)·AN if AN is positive, else 2·AN.
Note that u is at most k in any V(k,u) calculation, so there are N*(N-1)/2 possible values of (k,u), so the method as outlined uses O(N²) space and O(N³) time.
Here's a little insight that might enable you or someone else to come up with a really fast solution. Note that for an optimal solution, you can safely assume that at each step either you increase the weight by +1 from the previous weight, or you decrease the weight all the way down to the minimum of 2. To see this, suppose you have an optimal solution that violates the property. Then you have some weight > 2 at some position i-1 and the next weight is also > 2 at position i but not an increase. Now consider the maximal length weakly increasing sub-sequence of weights in the optimal solution starting at position i (weakly increasing means that at each step in the sub-sequence, the weight does not decrease). By assumption, the optimal solution with this sub-sequence is no worse than the same solution except with the sub-sequence having 1 subtracted from all its weights. But this means that increasing all the weights in the sub-sequence by 1 will also not make the optimal solution any worse. Thus for an optimal solution, at each step you can safely assume that either you increase the weight by 1 or you set the weight to the minimum of 2.

Algorithm to compute k fractions of form 1/r summing up to 1

Given k, we need to write 1 as a sum of k fractions of the form 1/r.
For example,
For k=2, 1 can uniquely be written as 1/2 + 1/2.
For k=3, 1 can be written as 1/3 + 1/3 + 1/3 or 1/2 + 1/4 + 1/4 or 1/6 + 1/3 + 1/2
Now, we need to consider all such set of k fractions that sum upto 1 and return the highest denominator among all such sets; for instance, the sample case 2, our algorithm should return 6.
I came across this problem in a coding competition and couldn't come up with an algorithm for the same. A bit of Google search later revealed that such fractions are called Egyption Fractions but probably they are set of distinct fractions summing upto a particular value (not like 1/2 + 1/2). Also, I couldn't find an algo to compute Egyption Fractions (if they are at all helpful for this problem) when their number is restricted by k.
If all you want to do is find the largest denominator, there's no reason to find all the possibilities. You can do this very simply:
public long largestDenominator(int k){
long denominator = 1;
for(int i=1;i<k;i++){
denominator *= denominator + 1;
}
return denominator;
}
For you recursive types:
public long largestDenominator(int k){
if(k == 1)
return 1;
long last = largestDenominator(k-1);
return last * (last + 1); // or (last * last) + last)
}
Why is it that simple?
To create the set, you need to insert the largest fraction that will keep it under 1 at each step(except the last). By "largest fraction", I mean by value, meaning the smallest denominator.
For the simple case k=3, that means you start with 1/2. You can't fit another half, so you go with 1/3. Then 1/6 is left over, giving you three terms.
For the next case k=4, you take that 1/6 off the end, since it won't fit under one, and we need room for another term. Replace it with 1/7, since that's the biggest value that fits. The remainder is 1/42.
Repeat as needed.
For example:
2 : [2,2]
3 : [2,3,6]
4 : [2,3,7,42]
5 : [2,3,7,43,1806]
6 : [2,3,7,43,1807,3263442]
As you can see, it rapidly becomes very large. Rapidly enough that you'll overflow a long if k>7. If you need to do so, you'll need to find an appropriate container (ie. BigInteger in Java/C#).
It maps perfectly to this sequence:
a(n) = a(n-1)^2 + a(n-1), a(0)=1.
You can also see the relationship to Sylvester's sequence:
a(n+1) = a(n)^2 - a(n) + 1, a(0) = 2
Wikipedia has a very nice article explaining the relationship between the two, as pointed out by Peter in the comments.
I never heard of Egyptian fractions before but here are some thoughts:
Idea
You can think of them geometrically:
Start with a unit square (1x1)
Draw either vertical or horizontal lines dividing the square into equal parts.
Repeat optionally the drawing of lines inside any of the sub-boxes evenly.
Stop any time you want.
The rectangles present will form a set of fractions of the form 1/n that add to 1.
You can count them and they might equal your 'k'.
Depending on how many equal sections you divided a rectangle into, it will tell whether you have 1/2 or 1/3 or whatever. 1/6 is 1/2 of 1/3 or 1/3 of 1/2. (i.e. You dived by 2 and then one of the sub-boxes by 3 OR the other way around.)
Idea 2
You start with 1 box. This is the fraction 1/1 with k=1.
When you sub-divide by n you add n to the count of boxes (k or of fractions summed) and subtract 1.
When you sub-divide any of those boxes, again, subtract 1 and add n, the number of divisions. Note that n-1 is the number of lines you drew to divide them.
More
You are going to start searching for the answer with k. Obviously k * 1/k = 1 so you have one solution right there.
How about k-1?
There's a solution there: (k-2) * 1/(k-1) + 2 * (1/((k-1)*2))
How did I get that? I made k-1 equal sections (with k-2 vertical lines) and then divided the last one in half horizontally.
Each solution is going to consist of:
taking a prior solution
using j less lines and some stage and dividing one of the boxes or sub-boxes into j+1 equal sections.
I don't know if all solutions can be formed by repeating this rule starting from k * 1/k
I do know you can get effective duplicates this way. For example: k * 1/k with j = 1 => (k-2) * 1/(k-1) + 2 * (1/((k-1)*2)) [from above] but k * 1/k with j = (k-2) => 2 * (1/((k-1)*2)) + (k-2) * 1/(k-1) [which just reverses the order of the parts]
Interesting
k = 7 can be represented by 1/2 + 1/4 + 1/8 + ... + 1/(2^6) + 1/(2^6) and the general case is 1/2 + ... + 1/(2^(k-1)) + 1/(2^(k-1)).
Similarly for any odd k it can be represented by 1/3 + ... + 3 * [1/(3^((k-1)/2)].
I suspect there are similar patterns for all integers up to k.

Interview question - Finding numbers

I just got this question on a SE position interview, and I'm not quite sure how to answer it, other than brute force:
Given a natural number N, find two numbers, A and P, such that:
N = A + (A+1) + (A+2) + ... + (A+P-1)
P should be the maximum possible.
Ex: For N=14, A = 2 and P = 4
N = 2 + (2+1) + (2+2) + (4+2-1)
N = 2 + 3 + 4 + 5
Any ideas?
If N is even/odd, we need an even/odd number of odd numbers in the sum. This already halfes the number of possible solutions. E.g. for N=14, there is no point in checking any combinations where P is odd.
Rewriting the formula given, we get:
N = A + (A+1) + (A+2) + ... + (A+P-1)
= P*A + 1 + 2 + ... + (P-1)
= P*A + (P-1)P/2 *
= P*(A + (P-1)/2)
= P/2*(2*A + P-1)
The last line means that N must be divisible by P/2, this also rules out a number of possibilities. E.g. 14 only has these divisors: 1, 2, 7, 14. So possible values for P would be 2, 4, 14 and 28. 14 and 28 are ruled our for obvious reasons (in fact, any P above N/2 can be ignored).
This should be a lot faster than the brute-force approach.
(* The sum of the first n natural numbers is n(n+1)/2)
With interview questions, it is often wise to think about what is probably the purpose of the question. If I would be asking you this question, it is not because I think you know the solution, but I want to see you finding the solution. Reformulating the problem, making implications, devising what is known, ... this is what I would like to see.
If you just sit and tell me "I do not know how to solve it", you immediately fail the interview.
If you say: I know how to solve it by brute force, and I am aware it will be probably slow, I will give you some hints or help you to get you started. If that does not help, you most likely fail (unless you show some extraordinary skills to compensate for the fact you are probably lacking something in the field of general problem analysis, e.g. you will show how to implement a solution paralelized for many cores or implemented on GPU).
If you bring me a ready solution, but you are unable to derive it, I will give you another similar problem, because I am not interested about solution, I am interested in your thinking.
A + (A+1) + (A+2) + ... + (A+P-1) simplifies to P*A + (P*(P-1)/2) resp P*(A+(P-1)/2).
Thus, you could just enumerate all divisors of N, and then test each divisor P to the following:
Is A = (N-(P*(P-1)/2))/P (solved the first simplification for A) an integral number? (I assume it should be an integral number, otherwise it would be trivial.) If so, return it as a solution.
Can be solved using 0-1 Knapsack solution .
Observation : N/2 + N/2 + 1 > N
so our series is 1,2,...,N/2
Consider the constraints of W=N and vi =1 for all elements, I think this trivially maps to 0-1 knapsack, O(n^2)
Here is a O(n) solution.
It uses the property of the sum of an arithmetic progression.
S = difference*(first_term + last_term)/2
Here our sum is N, the difference is P and first term is A.
Manipulation the above equation we get some equations and we can iterate P from 1 to n - 1 to get a valid A.
def solve(n,p):
return (2*n - (p**2) + p)/(2*p)
def condition(n,p,a):
if (2*n == (2*a*p) + (p**2) - p) and (a*-1 < 0):
return True
else:
return False
def find(n):
for x in xrange(n,-1,-1):
a = solve(n,x)
if condition(n,x,a):
return n,x,a

Resources