I am trying to solve this problem: https://www.urionlinejudge.com.br/judge/en/problems/view/1312
The XYZ TV channel is developing a new game show, where a contestant
has to make some choices in order to get a prize. The game consists of
a triangular stack of balls, each of them having an integer value, as
the following example shows.
The contestant must choose which balls he is going to take and his
prize is the sum of the values of those balls. However, the contestant
can take any given ball only if he also takes the balls directly on
top of it. This may require taking additional balls using the same
rule. Notice that the contestant may choose not to take any ball, in
which case the prize is zero.
The TV show director is concerned about
the maximum prize a contestant can make for a given stack. Since he is
your boss and he does not know how to answer this question, he
assigned this task to you.
Input
Each test case is described using several lines. The first line
contains an integer N representing the number of rows of the stack (1
≤ N ≤ 1000). The i th of the next N lines contains i integers Bij
(−105 ≤ Bij ≤ 105 for 1 ≤ j ≤ i ≤ N); the number Bij is the value of
the j th ball in the i th row of the stack (the first row is the
topmost one, and within each row the first ball if the leftmost one).
The last test case is followed by a line containing one zero.
Output
Sample Input | Sample Output
4 | 7
3 | 0
-5 3 | 6
-8 2 -8 |
3 9 -2 7 |
2 |
-2 |
1 -10 |
3 |
1 |
-5 3 |
6 -4 1 |
0 |
I'd love a pointer or two on how to solve this problem.
It seems like it is solvable using a DP approach, but I can't quite formulate the recurrence. The fact that two adjacent balls could have overlapping children is making things a bit difficult.
This is DP, but we're going sideways instead of top-down. Let's tilt the ball stack a little to the left, so we can look at the whole stack as a sequence of columns.
3 3 -8 7
-5 2 -2
-8 9
3
From this viewpoint the rule of the game becomes: if we want to take a ball, we also need to take the ball above, and the ball directly to its left.
Now, solving the problem. We'll calculate a quantity S[i, j] for each ball
-- this represents the best sum we could achieve if the ball at position [i, j] is taken (the `jth ball from the top of the ith column), while considering only the first i columns.
I claim that the following recurrence holds (with some sensible initial conditions):
S[i, j] = MAX(S[i-1, j] + C[i, j], S[i, j+1])
where C[i, j] is the sum of the first j balls in the ith column.
Let's break that down a bit. We want to calculate S[i, j].
We have to take the ball at [i, j]. And let's suppose for now that this is the bottom-most ball we take from this column.
This requires all the balls in this column above it to be taken, with the sum (including [i, j] itself) being C[i, j].
It also requires the ball at [i-1, j] to be taken (unless we're at the leftmost column, of course). We know that the best sum from taking this ball is S[i-1, j], by definition.
So the best possible total sum is: S[i-1, j] + C[i, j], or just C[i, j] for the leftmost column.
But we can choose differently and take more balls from this column (if we have more balls). We need to calculate and take the maximum value out of S[i-1, j] + C[i, j], S[i-1, j+1] + C[i, j+1], and so on, all the way down to the bottom of the pile.
With a little induction it's easy to see this is equal to MAX(S[i-1, j] + C[i, j], S[i, j+1]).
The implementation should be obvious now. We process the stack column-by-column, in each column calculate the partial sum C[i, j] from the top down, then work out S[i, j] from bottom up.
Finally, just take the maximum value of S[i, j] we've encountered (or 0) as the answer.
This runs in linear time to the number of balls, so O(N^2).
To illustrate, here's (C[i, j], S[i, j]) pairs for the given example.
( 3, 3) ( 3,7) ( -8,-1) (7,6)
( -2,-2) ( 5,7) (-10,-3)
(-10,-7) (14,7)
( -7,-7)
(Updated with better understanding from Worakarn Isaratham's answer.)
We can have a naive recurrence with O(N^2) search space (note that there are O(N^2) total balls so to do any better we could not examine all entries) by iterating over the diagonals. Let's say southwest.
\ jth NW diagonal
x
x o
A o x
x o x o
x o x B x / ...etc
C o x o x o / 3rd iteration
x o D o E F x / 2nd iteration
x o x o x o x o / 1st iteration (ith SW diagonal)
x o x o x o x G x
/ / / \
Each choice along a southwest diagonal, would restrict all the rest of the choices and sums below a northwest diagonal (e.g., being able to choose E means we've only chosen as far as the FG diagonal on previous iterations and choosing it would restrict all subsequent choices below the AE diagonal.
Say we label southwest diagonals as i and our northwest bound as j, and have a function sum_northwest that calculates in O(1) (using prefix sums) and takes as parameters one northwest diagonal and a southwest bound. Then, if f(i, j) represents the optimal choice up to the ith southwest column with nothwest bound j:
f(i, j) = max(
// Skip choosing from
// this southwest diagonal
f(i - 1, j),
// Choose this northwest diagonal
// on this southwest diagonal
sum_northwest(j - 1, i) + f(i - 1, j - 1),
// Choose an earlier northwest diagonal,
// but then we are obliged to also
// include this northwest diagonal
sum_northwest(j - 1, i) + f(i, j - 1)
)
Time complexity is O(|I| * |J|), assuming we are tabling results.
JavaScript code (not optimised):
function sum_northwest(M, j, i){
return M[j].slice(0, i + 1)
.reduce((a, b) => a + b, 0)
}
function f(M, i, j){
if (i < 0 || j < 1 || i >= M[M.length-j].length)
return 0
let this_northwest =
sum_northwest(M, M.length - j, i)
return Math.max(
f(M, i - 1, j),
this_northwest + f(M, i - 1, j - 1),
this_northwest + f(M, i, j - 1)
)
}
var M = [
[ 3, 3,-8, 7],
[-5, 2,-2],
[-8, 9],
[ 3]
]
console.log(f(M, 3, 4))
M = [
[-2,-10],
[ 1]
]
console.log(f(M, 1, 2))
M = [
[ 1, 3, 1],
[-5,-4],
[ 6]
]
console.log(f(M, 2, 3))
O
/\
/ \
A/ \B
/ \ / \
/ \/ \
C M D
Suppose we take a ball at M, then we also need to take all the balls from the region MAOB. We are left with 2 triangles: CAM and MBD, and we need to select balls from these two triangles to maximize the points. This is the same problem, but with a smaller input.
So we define the value function over the sets of all sub-triangles in the stack
Let C[i,j,h] = maximum points from a sub-triangle with the top at (i,j) and with height = h (I use right-angled triangles to illustrate here because it is easier to draw)
|\
| \
| \
| \
| A \
| |\ \
| | \ \
| | \ \
| |D \E \
| |\ |\ \
| | \ | \ \
| |__\|__\ \
| B M C \
|_____________\
A = (i,j)
B = (i+h, j)
C = (i+h, j+h)
M = (i+h, j+k)
D = (i, j+h-k)
E = (i+k, j+k)
Recursive formula:
C[i,j,h] = max(
C[i,j,h-1] // pick no ball at line i+h
C[i,j+h-k,k] + C[i+k,j+k,h-k] + sum(ADME) for k from 0 to h // if pick a ball at (i+h, j+k)
)
I will show a solution in O(N log N) time complexity and O(N) memory complexity.
First of all, you are correct we will use a Dynamic Programing approach. The data structure we will use will be a triangle of the same size. Each ball in the new triangle will be the value of the competitor if it took that ball. We can build it in O(N) time - top to bottom.
Now we need to notice some interesting claim: The ball with the highest value in the new triangle will be taken (unless it's negative in which case we will not take any thing).
Proof: (Quite straightforward) If not taken, than we can take it and necessarily get the total value higher.
Another interesting claim: All the balls below (that will take it if they were taken) the the ball with highest score in the data structure - will not be taken.
Proof: If they were taken it mean that the value of them is positive without the ball with the highest value and that means that their value is higher which is impossible.
Now to the algorithm:
Build the data structure.
Set of all taken items = {}
while there are positive elements in the structure:
Take highest one - put in the set.
make all below it 0, and put then in the set.
make all above it negative infinity.
Rebuild the data structure for the rest.
Return the set
This will always be optimal - we take the ball with highest value, we will never miss a ball that ban help us, and we will never miss other balls since we rebuild the data structure.
Memory complexity is simple: O(N) for the data structure.
Time complexity is tricky: Creating the data structure is O(N), each time in the loop we remove at least half of the elements and we will not recompute for them, therefore number of iterations will be logarithmic in N so O(N log N).
Related
A friend gave me this problem as a challenge, and I've tried to find a problem like this on LeetCode, but sadly could not.
Question
Given a line of people numbered from 1 to N, and a list of pairs of M enemies, find the total number of sublines with people that contain no two people that are enemies.
Example: N = 5, enemies = [[3,4], [3,5]]
Answer: 9
Explanation: These continuous subintervals are:
[1,1], [2,2], [3,3], [1,2], [2,3], [1,3], [4,4], [4,5], [5,5]
My approach
We define a non-conflicting interval as a contiguous interval from (and including) [a,b] where no two people are enemies in that interval.
Working backwards, if I know there is a non conflicting interval from [1,3] like in the example given above, I know the number of contiguous intervals between those two numbers is n(n+1)/2 where n is the length of the interval. In this case, the interval length is 3, and so there are 6 intervals between (and including) [1,3] that count.
Extending this logic, if I have a list of all non-conflicting intervals, then the answer is simply the sum of (n_i*(n_i+1))/2 for every interval length n_i.
Then all I need to do is find these intervals. This is where I'm stuck.
I can't really think of a similar programming problem. This seems similar, but the opposite of what the Merge Intervals problem on leetcode asks for. In that problem we're sorta given the good intervals and are asked to combine them. Here we're given the bad.
Any guidance?
EDIT: Best I could come up with:
Does this work?
So let's define max_enemy[i] as the largest enemy that is less that a particular person i, where i is the usual [1,N]. We can generate this value in O(M) time simply using a the following loop:
max_enemy = [-1] * (N+1) # -1 means it doesn't exist
for e1, e2 in enms:
e1, e2 = min(e1,e2), max(e1, e2)
max_enemy[e2] = max(max_enemy[e2], e1)
Then if we go through the person's array keeping a sliding window. The sliding window ends as soon as we find a person i who has: max_enemy[i] < i. This way we know that including this person will break our contiguous interval. So we now know our interval is [s, i-1] and we can do our math. We reset s=i and continue.
Here is a visualization of how this works visually. We draw a path between any two enemies:
N=5, enemies = [[3,4], [3,5]]
1 2 3 4 5
| | |
-----
| |
--------
EDIT2: I know this doesn't work for N=5, enemies=[[1,4][3,5]], currently working on a fix, still stuck
You can solve this in O(M log M) time and O(M) space.
Let ENDINGAT(i) be the number of enemy-free intervals ending at position/person i. This is also the size of the largest enemy-free interval ending at i.
The answer you seek is the sum of all ENDINGAT(i) for every person i.
Let NEAREST(i) be the nearest enemy of person i that precedes person i. Let it be -1 if i has no preceding enemies.
Now we can write a simple formula to calculate all the ENDINGAT(values):
ENDINGAT(1) = 1, since there is only one interval ending at 1. For larger values:
ENDINGAT(i) = MIN( ENDINGAT(i-1)+1, i-NEAREST(i) )
So, it is very easy to calculate all the ENDINGAT(i) in order, as long as we can have all the NEAREST(i) in order. To get that, all you need to do is sort the enemy pairs by the highest member. Then for each i you can walk over all the pairs ending at i to find the closest one.
That's it -- it turns out to be pretty easy. The time is dominated by the O(M log M) time required to sort the enemy pairs, unless N is much bigger than M. In that case, you can skip runs of ENDINGAT for people with no preceding enemies, calculating their effect on the sum mathematically.
There's a cool visual way to see this!
Instead of focusing the line, let's look at the matrix of pairs of players. If ii and j are enemies, then the effect of this enemiship is precisely to eliminate from consideration (1) this interval, and (2) any interval strictly larger than it. Because enemiship is symmetric, we may as well just look at the upper-right half of the matrix, and the diagonal; we'll use the characters
"X" to denote that a pair is enemies,
"*" to indicate that a pair has been obscured by a pair of enemies, and
"%" in the lower half to mark it as not part of the upper-half matrix.
For the two examples in your code, observe their corresponding matrices:
# intervals: 9 # intervals: 10
0 1 2 3 4 0 1 2 3 4
------------------------ ------------------------
* * | 0 * * | 0
% * * | 1 % X * | 1
% % X X | 2 % % X | 2
% % % | 3 % % % | 3
% % % % | 4 % % % % | 4
The naive solution, provided below, solves the problem in O(N^2 M) time and O(N^2) space.
def matrix(enemies):
m = [[' ' for j in range(N)] for i in range(N)]
for (i,j) in enemies:
m[i][j] = 'X' #Mark Enemiship
# Now mark larger intervals as dead.
for q in range(0,i+1):
for r in range(j,N):
if m[q][r] == ' ':
m[q][r] = '*'
num_int = 0
for i in range(N):
for j in range(N):
if(j < i):
m[i][j] = '%'
elif m[i][j] == ' ':
num_int+=1
print("# intervals: ", num_int)
return m
To convince yourself further, here are the matrices where
player 2 is enemies with himself, so that there is a barrier, and there are two smaller versions of the puzzle on the intervals [0,1] and [3,4] each of which admits 3 sub-intervals)
Every player is enemies with the person two to their left, so that only length-(1 or 0) intervals are allowed (of which there are 4+5=9 intervals)
# intervals: 6 # intervals: 9
0 1 2 3 4 0 1 2 3 4
---------[===========+ --------[============+
* * * || 0 X * * || 0
% * * * || 1 % X * || 1
% % X * * II 2 % % X II 2
% % % | 3 % % % | 3
% % % % | 4 % % % % | 4
Complexity: Mathematically the same as sorting a list, or validating that it is sorted. that is, O(M log M) in the worst case, and O(M) space to sort, and still at least O(M) time in the best case to recognize if the list is sorted.
Bonus: This is also an excellent example to illustrate power of looking at the identity a problem, rather than its solution. Such a view of the of the problem will also inform smarter solutions. We can clearly do much better than the code I gave above...
We would clearly be done, for instance, if we could count the number of un-shaded points, which is the area of the smallest convex polygon covering the enemiships, together with the two boundary points. (Finding the two additional points can be done in O(M) time.) Now, this is probably not a problem you can solve in your sleep, but fortunately the problem of finding a convex hull, is so natural that the algorithms used to do it are well known.
In particular, a Graham Scan can do it in O(M) time, so long as we happen to be given the pairs of enemies so that one of their coordinates is sorted. Better still, once we have the set of points in the convex hull, the area can be calculated by dividing it into at most M axis-aligned rectangles. Therefore, if enemy pairs are sorted, the entire problem could be solved in O(M) time. Keep in mind that M could be dramatically than N, and we don't even need to store N numbers in an array! This corresponds to the arithmetic proposed to skip lines in the other answer to this question.
If they are not sorted, other Convex Hull algorithms yield an O(M log M) running time, with O(M) space, as given by #Matt Timmermans's solution. In fact, this is the general lower bound! This can be shown with a more complicated geometric reduction: if you can solve the problem, then you can compute the sum of the heights of each number, multiplied by its distance to "the new zero", of agents satisfying j+i = N. This sum can be used to compute distances to the diagonal line, which is enough to sort a list of numbers in O(M) time---a problem which cannot be solved in under O(M log M) time for adversarial inputs.
Ah, so why is it the case that we can get an O(N + M) solution by manually performing this integration, as done explicitly in the other solution? It is because we can sort the M numbers if we know that they fall into N bins, by Bucket Sort.
Thanks for sharing the puzzle!
I know how to calculate the total number of combinations of n different objects taken k at a time, with replacement:
(n+k-1)!/k!/(n-1)!
What I need is a formula or algorithm to recover the i-th such combination from an ordered list.
Say I have an ordered list of all combinations of a,b,c taken 3 at a time (so n=3 and k=3):
1 aaa
2 aab
3 aac
4 abb
5 abc
6 acc
7 bbb
8 bbc
9 bcc
10 ccc
How would I calculate the i-th (say 7-th) combination in this list, without first enumerating them all ? Enumerating will be very inefficient for any but the simplest cases, if I am only interested in a few specific combinations. For instance, there are 119,877,472 combinations of 64 items taken 6 at a time.
Needless to say, I need a solution for arbitrary n, k and i.
The reverse function (given the combination, how to calculate its index) would also be interesting.
I found one similar question, but it was about permutations, not combinations:
I want to get a specific combination of permutation?
And there are many ways to list all the combinations, such as mentioned here:
How to generate all permutations and combinations with/without replacement for distinct items and non distinct items (multisets)
But they don't give the functions I need
The algorithm you are interested in is very easy to implement. The first thing you should understand is why actually C(k, n + k - 1) = C(n - 1, n + k - 1) = (n + k - 1)! / k! / (n - 1)! formula works. Formula says that the number of ways to take k items out of n is the same as to take n-k items out of n.
Lets say your objects are balls of some color. There are n different colors numbered from 1 to n. You need to calculate the number of ways to have k balls. Imagine initially k white balls (without any color) so you need to paint them in different ways. Arrange the balls in a row. Choose some k1 ≥ 0 balls from the left to paint in color #1, next k2 ≥ 0 balls we paint in #2, and so on... We have ∑ki = k. A series of k1 balls painted in color #1 is followed by k2 of color #2, next by k3 of color #3 etc...
We can do the same painting in a slightly different way however. In order to separate ki-1- and ki-colored balls we would use delimiters. In total we should have n - 1 such delimiters to be placed among the balls. The delimiters are ordered, one that separates 1-colored and 2-colored balls should appear before another that separates 2-colored and 3-colored. If some ki = 0 then corresponding delimiters appear one by one. We have to arrange delimiters and balls in some way.
Interestingly we can imagine now that both n - 1 delimiters and k balls are just objects initially placed in a row. We have to choose either n - 1 of them to declare selected objects to be delimiters or k objects to be balls. And that's where well-known combination formula can be applied.
Example for your case:
o - ball
. - delimiter
a, b, c - colors
We have:
ooo.. => aaa
oo.o. => aab
oo..o => aac
o.oo. => abb
o.o.o => abc
o..oo => acc
.ooo. => bbb
.oo.o => bbc
.o.oo => bcc
..ooo => ccc
Notice the pattern how delimiters move from right to left.
Algorithm
Now to the question of how to get the p-th arrangement. Efficient algorithm description follows. Remember that we have k balls and nd = n - 1 delimiters. We will be placing delimiters one by one first trying their rightmost positions. Consider leaving current delimiter at its current position, calculate the number of combinations to place the remaining objects to the right, let the number be some N. Compare N with p, if p is greater or equal to N then reduce p by N (p <- p - N) and we should move current delimiter left by 1. Else if p is lower than N then we will not move current delimiter but proceed to the next one trying to move it again from the rightmost position. Note that p-th arrangement is zero-based.
Having "converted" some i-th object to j-th delimiter we have N = C(nd - j, nd + k - i) number of ways to arrange remaining k - i + j balls and nd - j delimiters.
Since we'll often refer to binomial coefficients we'd better make their precalculation.
The reverse function may be implemented accordingly. You have positions for every delimiter. Accumulate the number of ways to arrange remaining objects while moving ordinary delimiter to its place from the rightmost position.
Example:
3 balls, 2 delimiters, find 7-th arrangement (which is bbc or .oo.o)
Place delimiters to the rightmost position: ooo... Let first delimiter be current.
Calculate N = C(1, 1) = 1, p ≥ N so we reduce p by N getting p = 6. At the same time we move current delimiter 1 pos left getting oo.o..
Calculate N = C(1, 2) = 2, p ≥ N, reduce p by N getting p = 6 - 2 = 4. Move getting o.oo..
Calculate N = C(1, 3) = 3, p ≥ N once again, move and reduce p getting p = 1 and .ooo..
Calculate N = C(1,4) = 4, p < N. Good, we've found final position for the first delimiter so leave it there and take second delimiter as current.
Calculate N = C(0,0) = 1, p ≥ N, p = 1 - 1 = 0, move, .oo.o.
Calculate N = C(0,1) = 1, p < N, found final position for the second delimiter. Resulting arrangement is .oo.o => bbc.
EDIT #1. Changed the algo description and added example.
here is the function (not optimized but working):
findcomb <- function(n, k, p) {
# n = nr of object types (colors, letters etc)
# k = number of objects (balls) to select
# p = 0-based index of target combination
# return = positions of delimiters at index p
nd <- n-1 #nr of delimiters: 1 - nr of colors
pos <- seq(n+k-nd, n+k-1) #original positions of delimiters, all at right
for (j in 1:(nd-1)) {
s <- 0 #cumulative nr of accounted-for combinations with this delimiter
while (TRUE) {
N <- choose(nd+k-pos[j], nd-j)
if (s + N <= p) {
pos[j] <- pos[j] - 1
s <- s + N
} else break
}
p <- p - s
}
#last delimiter:
pos[nd] <- pos[nd] - p
pos
}
I encountered this question in an interview and could not figure it out. I believe it has a dynamic programming solution but it eludes me.
Given a number of bricks, output the total number of 2d pyramids possible, where a pyramid is defined as any structure where a row of bricks has strictly less bricks than the row below it. You do not have to use all the bricks.
A brick is simply a square, the number of bricks in a row is the only important bit of information.
Really stuck with this one, I thought it would be easy to solve each problem 1...n iteratively and sum. But coming up with the number of pyramids possible with exactly i bricks is evading me.
example, n = 6
X
XX
X
XX XXX
X
XXX XXXX
XX X
XXX XXXX XXXXX
X
XX XX X
XXX XXXX XXXXX XXXXXX
So the answer is 13 possible pyramids from 6 bricks.
edit
I am positive this is a dynamic programming problem, because it makes sense to (once you've determined the first row) simply look to the index in your memorized array of your remainder of bricks to see how many pyramids fit atop.
It also makes sense to consider bottom rows of width at least n/2 because we can't have more bricks atop than on the bottom row EXCEPT and this is where I lose it and my mind falls apart, in certain (few cases) you can I.e. N = 10
X
XX
XXX
XXXX
Now the bottom row has 4 but there are 6 left to place on top
But with n = 11 we cannot have a bottom row with less than n/2 bricks. There is another wierd inconsistency like that with n = 4 where we cannot have a bottom row of n/2 = 2 bricks.
Let's choose a suitable definition:
f(n, m) = # pyramids out of n bricks with base of size < m
The answer you are looking for now is (given that N is your input number of bricks):
f(N, N+1) - 1
Let's break that down:
The first N is obvious: that's your number of bricks.
Your bottom row will contain at most N bricks (because that's all you have), so N+1 is a sufficient lower bound.
Finally, the - 1 is there because technically the empty pyramid is also a pyramid (and will thus be counted) but you exclude that from your solutions.
The base cases are simple:
f(n, 0) = 1 for any n >= 0
f(0, m) = 1 for any m >= 0
In both cases, it's the empty pyramid that we are counting here.
Now, all we need still is a recursive formula for the general case.
Let's assume we are given n and m and choose to have i bricks on the bottom layer. What can we place on top of this layer? A smaller pyramid, for which we have n - i bricks left and whose base has size < i. This is exactly f(n - i, i).
What is the range for i? We can choose an empty row so i >= 0. Obviously, i <= n because we have only n bricks. But also, i <= m - 1, by definition of m.
This leads to the recursive expression:
f(n, m) = sum f(n - i, i) for 0 <= i <= min(n, m - 1)
You can compute f recursively, but using dynamic programming it will be faster of course. Storing the results matrix is straightforward though, so I leave that up to you.
Coming back to the original claim that f(N, N+1)-1 is the answer you are looking for, it doesn't really matter which value to choose for m as long as it is > N. Based on the recursive formula it's easy to show that f(N, N + 1) = f(N, N + k) for every k >= 1:
f(N, N + k) = sum f(N - i, i) for 0 <= i <= min(N, N + k - 1)
= sum f(N - i, i) for 0 <= i <= N
= sum f(N - i, i) for 0 <= i <= min(N, N + 1 - 1)
In how many ways can you build a pyramid of width n? By putting any pyramid of width n-1 or less anywhere atop the layer of n bricks. So if p(n) is the number of pyramids of width n, then p(n) = sum [m=1 to n-1] (p(m) * c(n, m)), where c(n, m) is the number of ways you can place a layer of width m atop a layer of width n (I trust that you can work that one out yourself).
This, however, doesn't place a limitation on the number of bricks. Generally, in DP, any resource limitation must be modeled as a separate dimension. So your problem is now p(n, b): "How many pyramids can you build of width n with a total of b bricks"? In the recursive formula, for each possible way of building a smaller pyramid atop your current one, you need to refer to the correct amount of remaining bricks. I leave it as a challenge for you to work out the recursive formula; let me know if you need any hints.
You can think of your recursion as: given x bricks left where you used n bricks on last row, how many pyramids can you build. Now you can fill up rows from either top to bottom row or bottom to top row. I will explain the former case.
Here the recursion might look something like this (left is number of bricks left and last is number of bricks used on last row)
f(left,last)=sum (1+f(left-i,i)) for i in range [last+1,left] inclusive.
Since when you use i bricks on current row you will have left-i bricks left and i will be number of bricks used on this row.
Code:
int calc(int left, int last) {
int total=0;
if(left<=0) return 0; // terminal case, no pyramid with no brick
for(int i=last+1; i<=left; i++) {
total+=1+calc(left-i,i);
}
return total;
}
I will leave it to you to implement memoized or bottom-up dp version. Also you may want to start from bottom row and fill up upper rows in pyramid.
Since we are asked to count pyramids of any cardinality less than or equal to n, we may consider each cardinality in turn (pyramids of 1 element, 2 elements, 3...etc.) and sum them up. But in how many different ways can we compose a pyramid from k elements? The same number as the count of distinct partitions of k (for example, for k = 6, we can have (6), (1,5), (2,4), and (1,2,3)). A generating function/recurrence for the count of distinct partitions is described in Wikipedia and a sequence at OEIS.
Recurrence, based on the Pentagonal number Theorem:
q(k) = ak + q(k − 1) + q(k − 2) − q(k − 5) − q(k − 7) + q(k − 12) + q(k − 15) − q(k − 22)...
where ak is (−1)^(abs(m)) if k = 3*m^2 − m for some integer m and is 0 otherwise.
(The subtracted coefficients are generalized pentagonal numbers.)
Since the recurrence described in Wikipedia obliges the calculation of all preceding q(n)'s to arrive at a larger q(n), we can simply sum the results along the way to obtain our result.
JavaScript code:
function numPyramids(n){
var distinctPartitions = [1,1],
pentagonals = {},
m = _m = 1,
pentagonal_m = 2,
result = 1;
while (pentagonal_m / 2 <= n){
pentagonals[pentagonal_m] = Math.abs(_m);
m++;
_m = m % 2 == 0 ? -m / 2 : Math.ceil(m / 2);
pentagonal_m = _m * (3 * _m - 1);
}
for (var k=2; k<=n; k++){
distinctPartitions[k] = pentagonals[k] ? Math.pow(-1,pentagonals[k]) : 0;
var cs = [1,1,-1,-1],
c = 0;
for (var i in pentagonals){
if (i / 2 > k)
break;
distinctPartitions[k] += cs[c]*distinctPartitions[k - i / 2];
c = c == 3 ? 0 : c + 1;
}
result += distinctPartitions[k];
}
return result;
}
console.log(numPyramids(6)); // 13
I am reading Thoman Cormen's "Introduction to Algorithms" and I have problems understanding the algorithm written below.
Matrix-Chain-Order(p)
1 n ← length[p] − 1
2 for i ← 1 to n
3 do m[i, i] ← 0
4 for l ← 2 to n //l is the chain length.
5 do for i ← 1 to n − l + 1 // what is this?
6 do j ← i + l − 1 // what is this?
7 m[i, j] ← ∞
8 for k ← i to j − 1
9 do q ← m[i, k] + m[k + 1, j] + pi−1pkpj
10 if q < m[i, j]
11 then m[i, j] ← q
12 s[i, j] ← k
13 return m and s
Now, I know how the algorithm works. I know how to proceed in constructing the table and all that. In other words I know what happens up to line 4 and I also know what 9 to 13 is about.
I have problems understanding the subtleties of the "for" loops though. Lines 4 to 8 are difficult to understand. In line 5 why does i go up to n-l+1 and why is j in line 6 set to i+l-1. In line 7 ,m[i, j] is initialized for the comparison in line 10 but then again line 8 is a mystery.
I was just going through the algorithm definition on wikipedia and it's pretty comprehensive there. I'll try to explain you how I understood the solution.
The crux of the problem is we are basically trying to 'parenthesise' i.e. prioritize how we chain our matrices so that they are multiplied most efficiently and it's reflected in this line of code:
q = m[i,k] + m[k+1,j] + p[i-1]*p[k]*p[j];
To understand the above stand, first let's establish that i and j are fixed here i.e. we are trying to compute m[i,j] or the most efficient way to multiply matrices A[i..j] and k is the variable.
So at a very high level if i=1 and j=3 and the matrices are :
(A*B)*C //We are trying to establish where the outer most parenthesis should be
We don't know where it should be, hence we try all possibilities and pick the combination where m[i,j] is minimized. So we try:
i=1 and j=3
A*(B*C) //k=1
(A*B)*C //k=2
So clearly k should vary from i to j-1 which is reflected in the loop as we try all possible combinations and take the most efficient one. So for any k we'll have two partitions: A[i..k] and A[k+1...j]
So the cost of multiplication of A[i..j] for this partition of k is:
m[i,k] //Minimum cost of multiplication of A[i..k]
m[k+1,j] //Minimum cost of multiplication of A[k+1..j]
p[i-1]*p[k]*p[j]; //Final cost of multiplying the two partitions i.e. A[i..k] and A[k+1..j], where p contains the dimensions of the matrices.
A is a 10 × 30 matrix, B is a 30 × 5 matrix, and C is a 5 × 60 matrix. Then,
p[] = [10,30,5,60] i.e. Matrix Ai has dimension p[i-1] x p[i] for i = 1..n
This is what dynamic programming is all about. So we try all combinations of k and calculate m[i,j] but for that we also need to calculate m[i,k] and m[k+1,j] i.e. we break our problem down into smaller sub problems where the concept of chain length comes in.
So for all the matrices A[i..n] we calculate the most efficient way of multiplying a smaller chain of matrices of length l.
The smallest value of l is obviously 2 and the largest is n which is what we would get after we solve the smaller sub problems like I explained.
Let's come to the piece of code you are having trouble understanding:
for l ← 2 to n //l is the chain length.
do for i ← 1 to n − l + 1
do j ← i + l − 1
m[i, j] ← ∞
Now let's again consider a smaller example of 4 matrices H,I,J,K and you are looking at first chain lengths of 2. So when traversing the array of matrices.
A[1..4] = H,I,J,K //where A[1] = H and A[4] = K
For l = 2
Our loop should go from i=1 to i=3, as for every i we are looking at the chain of length 2.
So when i = 1, we would compute
m[1,2] i.e. minimum cost to multiply chain (H,I)
and when i = 3, we would compute
m[3,4] i.e. minimum cost to multiply chain (J,K)
When chain length is 3, we would have:
For i=1, j=3
m[i,j] -> m[1,3] i.e. minimum cost to multiply chain (H,I,J)
For i=2, j=4
m[i,j] -> m[2,4] i.e. minimum cost to multiply chain (I,J,K)
Hence when we define i to not exceed n-l+1 and j=i+l-1, we are making sure we are covering all the elements of the array and not exceeding the boundary condition i.e. the size of the array which is n and j defines the end of the chain starting from i with length l.
So the problem comes down to calculating m[i,j] for some i and j which as I explained earlier is solved by taking a partition k and trying out all possible values of k and then re-defining m[i,j] as the minimum value which is why it is initialized as ∞.
I hope my answer wasn't too long and it gives you clarity as to how the algorithm flows and helps you appreciate the sheer vastness of dynamic programming.
My input are three numbers - a number s and the beginning b and end e of a range with 0 <= s,b,e <= 10^1000. The task is to find the minimal Levenstein distance between s and all numbers in range [b, e]. It is not necessary to find the number minimizing the distance, the minimal distance is sufficient.
Obviously I have to read the numbers as string, because standard C++ type will not handle such large numbers. Calculating the Levenstein distance for every number in the possibly huge range is not feasible.
Any ideas?
[EDIT 10/8/2013: Some cases considered in the DP algorithm actually don't need to be considered after all, though considering them does not lead to incorrectness :)]
In the following I describe an algorithm that takes O(N^2) time, where N is the largest number of digits in any of b, e, or s. Since all these numbers are limited to 1000 digits, this means at most a few million basic operations, which will take milliseconds on any modern CPU.
Suppose s has n digits. In the following, "between" means "inclusive"; I will say "strictly between" if I mean "excluding its endpoints". Indices are 1-based. x[i] means the ith digit of x, so e.g. x[1] is its first digit.
Splitting up the problem
The first thing to do is to break up the problem into a series of subproblems in which each b and e have the same number of digits. Suppose e has k >= 0 more digits than s: break up the problem into k+1 subproblems. E.g. if b = 5 and e = 14032, create the following subproblems:
b = 5, e = 9
b = 10, e = 99
b = 100, e = 999
b = 1000, e = 9999
b = 10000, e = 14032
We can solve each of these subproblems, and take the minimum solution.
The easy cases: the middle
The easy cases are the ones in the middle. Whenever e has k >= 1 more digits than b, there will be k-1 subproblems (e.g. 3 above) in which b is a power of 10 and e is the next power of 10, minus 1. Suppose b is 10^m. Notice that choosing any digit between 1 and 9, followed by any m digits between 0 and 9, produces a number x that is in the range b <= x <= e. Furthermore there are no numbers in this range that cannot be produced this way. The minimum Levenshtein distance between s (or in fact any given length-n digit string that doesn't start with a 0) and any number x in the range 10^m <= x <= 10^(m+1)-1 is necessarily abs(m+1-n), since if m+1 >= n it's possible to simply choose the first n digits of x to be the same as those in s, and delete the remainder, and if m+1 < n then choose the first m+1 to be the same as those in s and insert the remainder.
In fact we can deal with all these subproblems in a single constant-time operation: if the smallest "easy" subproblem has b = 10^m and the largest "easy" subproblem has b = 10^u, then the minimum Levenshtein distance between s and any number in any of these ranges is m-n if n < m, n-u if n > u, and 0 otherwise.
The hard cases: the end(s)
The hard cases are when b and e are not restricted to have the form b = 10^m and e = 10^(m+1)-1 respectively. Any master problem can generate at most two subproblems like this: either two "ends" (resulting from a master problem in which b and e have different numbers of digits, such as the example at the top) or a single subproblem (i.e. the master problem itself, which didn't need to be subdivided at all because b and e already have the same number of digits). Note that due to the previous splitting of the problem, we can assume that the subproblem's b and e have the same number of digits, which we will call m.
Super-Levenshtein!
What we will do is design a variation of the Levenshtein DP matrix that calculates the minimum Levenshtein distance between a given digit string (s) and any number x in the range b <= x <= e. Despite this added "power", the algorithm will still run in O(n^2) time :)
First, observe that if b and e have the same number of digits and b != e, then it must be the case that they consist of some number q >= 0 of identical digits at the left, followed by a digit that is larger in e than in b. Now consider the following procedure for generating a random digit string x:
Set x to the first q digits of b.
Append a randomly-chosen digit d between b[i] and e[i] to x.
If d == b[i], we "hug" the lower bound:
For i from q+1 to m:
If b[i] == 9 then append b[i]. [EDIT 10/8/2013: Actually this can't happen, because we chose q so that e[i] will be larger then b[i], and there is no digit larger than 9!]
Otherwise, flip a coin:
Heads: Append b[i].
Tails: Append a randomly-chosen digit d > b[i], then goto 6.
Stop.
Else if d == e[i], we "hug" the upper bound:
For i from q+1 to m:
If e[i] == 0 then append e[i]. [EDIT 10/8/2013: Actually this can't happen, because we chose q so that b[i] will be smaller then e[i], and there is no digit smaller than 0!]
Otherwise, flip a coin:
Heads: Append e[i].
Tails: Append a randomly-chosen digit d < e[i], then goto 6.
Stop.
Otherwise (if d is strictly between b[i] and e[i]), drop through to step 6.
Keep appending randomly-chosen digits to x until it has m digits.
The basic idea is that after including all the digits that you must include, you can either "hug" the lower bound's digits for as long as you want, or "hug" the upper bound's digits for as long as you want, and as soon as you decide to stop "hugging", you can thereafter choose any digits you want. For suitable random choices, this procedure will generate all and only the numbers x such that b <= x <= e.
In the "usual" Levenshtein distance computation between two strings s and x, of lengths n and m respectively, we have a rectangular grid from (0, 0) to (n, m), and at each grid point (i, j) we record the Levenshtein distance between the prefix s[1..i] and the prefix x[1..j]. The score at (i, j) is calculated from the scores at (i-1, j), (i, j-1) and (i-1, j-1) using bottom-up dynamic programming. To adapt this to treat x as one of a set of possible strings (specifically, a digit string corresponding to a number between b and e) instead of a particular given string, what we need to do is record not one but two scores for each grid point: one for the case where we assume that the digit at position j was chosen to hug the lower bound, and one where we assume it was chosen to hug the upper bound. The 3rd possibility (step 5 above) doesn't actually require space in the DP matrix because we can work out the minimal Levenshtein distance for the entire rest of the input string immediately, very similar to the way we work it out for the "easy" subproblems in the first section.
Super-Levenshtein DP recursion
Call the overall minimal score at grid point (i, j) v(i, j). Let diff(a, b) = 1 if characters a and b are different, and 0 otherwise. Let inrange(a, b..c) be 1 if the character a is in the range b..c, and 0 otherwise. The calculations are:
# The best Lev distance overall between s[1..i] and x[1..j]
v(i, j) = min(hb(i, j), he(i, j))
# The best Lev distance between s[1..i] and x[1..j] obtainable by
# continuing to hug the lower bound
hb(i, j) = min(hb(i-1, j)+1, hb(i, j-1)+1, hb(i-1, j-1)+diff(s[i], b[j]))
# The best Lev distance between s[1..i] and x[1..j] obtainable by
# continuing to hug the upper bound
he(i, j) = min(he(i-1, j)+1, he(i, j-1)+1, he(i-1, j-1)+diff(s[i], e[j]))
At the point in time when v(i, j) is being calculated, we will also calculate the Levenshtein distance resulting from choosing to "stop hugging", i.e. by choosing a digit that is strictly in between b[j] and e[j] (if j == q) or (if j != q) is either above b[j] or below e[j], and thereafter freely choosing digits to make the suffix of x match the suffix of s as closely as possible:
# The best Lev distance possible between the ENTIRE STRINGS s and x, given that
# we choose to stop hugging at the jth digit of x, and have optimally aligned
# the first i digits of s to these j digits
sh(i, j) = if j >= q then shc(i, j)+abs(n-i-m+j)
else infinity
shc(i, j) = if j == q then
min(hb(i, j-1)+1, hb(i-1, j-1)+inrange(s[i], (b[j]+1)..(e[j]-1)))
else
min(hb(i, j-1)+1, hb(i-1, j-1)+inrange(s[i], (b[j]+1)..9),
he(i, j-1)+1, he(i-1, j-1)+inrange(s[i], (0..(e[j]-1)))
The formula for shc(i, j) doesn't need to consider "downward" moves, since such moves don't involve any digit choice for x.
The overall minimal Levenshtein distance is the minimum of v(n, m) and sh(i, j), for all 0 <= i <= n and 0 <= j <= m.
Complexity
Take N to be the largest number of digits in any of s, b or e. The original problem can be split in linear time into at most 1 set of easy problems that collectively takes O(1) time to solve and 2 hard subproblems that each take O(N^2) time to solve using the super-Levenshtein algorithm, so overall the problem can be solved in O(N^2) time, i.e. time proportional to the square of the number of digits.
A first idea to speed up the computation (works if |e-b| is not too large):
Question: how much can the Levestein distance change when we compare s with n and then with n+1?
Answer: not too much!
Let's see the dynamic-programming tables for s = 12007 and two consecutive n
n = 12296
0 1 2 3 4 5
1 0 1 2 3 4
2 1 0 1 2 3
3 2 1 1 2 3
4 3 2 2 2 3
5 4 3 3 3 3
and
n = 12297
0 1 2 3 4 5
1 0 1 2 3 4
2 1 0 1 2 3
3 2 1 1 2 3
4 3 2 2 2 3
5 4 3 3 3 2
As you can see, only the last column changes, since n and n+1 have the same digits, except for the last one.
If you have the dynamic-programming table for the edit-distance of s = 12001 and n = 12296, you already have the table for n = 12297, you just need to update the last column!
Obviously if n = 12299 then n+1 = 12300 and you need to update the last 3 columns of the previous table.. but this happens just once every 100 iteration.
In general, you have to
update the last column on every iterations (so, length(s) cells)
update the second-to-last too, once every 10 iterations
update the third-to-last, too, once every 100 iterations
so let L = length(s) and D = e-b. First you compute the edit-distance between s and b. Then you can find the minimum Levenstein distance over [b,e] looping over every integer in the interval. There are D of them, so the execution time is about:
Now since
we have an algorithm wich is