Say there's a matrix with N rows and M columns.
You start the traversal at the bottom left, and your current points P is 0, and space S which is larger than 0. At each point in the matrix, the coordinate is either empty or contains points. If the points have size X and value V, you can choose to pick up the points or not when you reach a coordinate.
For traversing the matrix, we can only go up by one row and choose from one of the three columns (i.e. (i + 1, j − 1), (i + 1, j), or (i + 1, j + 1))
Picking up the points increases P by V and decreases S by X.
I'm trying to write a dynamic programming algorithm that would traverse this and return the best path resulting in the largest number of points.
I figure the subproblems are:
L(N, j) = Null
L(i, 0) = max(L(i + 1, 0), L(i + 1, 1))
L(i, j) = max(L(i + 1, j − 1), L(i + 1, j), L(i + 1, j + 1))
L(i, M) = max(L(i + 1, j - 1), L(i + 1, j))
Would that work? How would I go about introducing this to an algorithm?
You can do it in two ways :
Recursive call for function which should cover all boundary/edge conditions
For example the function call would look like this :
function L(i,j, p, s) :
if(i<0 or j<0) return -1 #edge case
if(s<0) return -1 #out of space
if(p<0) return 0 #no possible outcome
if (s == 0) return p #the end
else return max{L(i + 1, j − 1, p+v, s-x), L(i + 1, j, p+v, s-x), L(i + 1, j + 1, p+v, s-x)}
Iterative with tracking with (s<0) condition and you can maintain the matrix for max S and P values for each step.
Related
We say that a sequence of numbers x(1),x(2),...,x(k) is zigzag if no three of its consecutive elements create a nonincreasing or nondecreasing sequence. More precisely, for all i=1,2,...,k-2 either
x(i) >( x(i+1),x(i-1) )
or
x(i) < ( x(i+1) , x(i-1))
I have two sequences of numbers a(1),a(2),...,a(n) and b(1),b(2),...,b(m). The problem is to compute the length of their longest common zigzag subsequence. In other words, you're going to delete elements from the two sequences so that they are equal, and so that they're a zigzag sequence. If the minimum number of elements required to do this is k then your answer is m+n-2k.
Note. sequences with length two and one are trivially zigzag
Now i tried writing a memoized recursive solution for the same using the below state variables
i= current position of sequence 1.
j= current position of sequence 2.
last= last taken number in the zigzag sequence currently being considered.
direction = current requirement of the number i.e. should it be greater than previous,less or same;
i call the below function with
magic(0,0,Integer.MIN_VALUE,0);
Here Integer.MIN_VALUE is used a sentinel value denoting no numbers are taken yet in the sequence.
The function is given below:
static int magic(int i, int j, int last, int direction) {
if (hm.containsKey(i + " " + j + " " + last + " " + direction))
return hm.get(i + " " + j + " " + last + " " + direction);
if (i == seq1.length || j == seq2.length) {
return 0;
}
int take_both = 0, leave_both = 0, leave1 = 0, leave2 = 0;
if (seq1[i] == seq2[j] && last == Integer.MIN_VALUE)
take_both = 1 + magic(i + 1, j + 1, seq1[i], direction); // this is the first digit hence direction is 0.
else if (seq1[i] == seq2[j] && (direction == 0 || direction == 1 && seq1[i] > last || direction == -1 && seq1[i] < last))
take_both = 1 + magic(i + 1, j + 1, seq1[i], last != seq1[i] ? (last > seq1[i] ? 1 : -1) : 2);
leave_both = magic(i + 1, j + 1, last, direction);
leave1 = magic(i + 1, j, last, direction);
leave2 = magic(i, j + 1, last, direction);
int ans;
ans = Math.max(Math.max(Math.max(take_both, leave_both), leave1), leave2);
hm.put(i + " " + j + " " + last + " " + direction, ans);
return ans;
}
Now the above code is working for as much test cases i could make, but the complexity is high.
How do i reduce the time complexity,can i eliminate some state variables here? is there a efficient way to do this?
First let's reduce the number of states: Let f(i, j, d) be the length of the longest common zig-zag sequence starting at position i in the first string and position j in the second string and starting with direction d (up or down).
We have the recurrence
f(i, j, up) >= MAX(i' > i, j' > j : f(i', j', up))
if s1[i] = s2[j]:
f(i, j, up) >= MAX(i' > i, j' > j, s1[i'] > x : f(i', j', down))
an similar for the down direction. Solving this in a straightforward way
will lead to a runtime of something like O(n4 · W) where W is the range of integers in the array. W is not polynomially bounded, so we definitely want to get rid of this factor, and ideally a couple of n factors along the way.
To solve the first part, you have to find the maximum f(i', j', up) with
i' > i and j' > j. This is a standard standard 2-d orthogonal range maximum query.
For the second case, you need to find the maximum (i', j', down) with i' > i, j' > j and s1[i'] > s1[i]. That is a range maximum query in the rectangle (i, ∞) x (j, ∞) x (s1[i], ∞).
Now having 3 dimensions here looks scary. However, if we process the states in say, decreasing order of i, then we can get rid of one dimension.
We thus reduced the problem to a range query in the rectangle (j, ∞) x (s1[i], ∞). Coordinate compression gets the dimension of values down to O(n).
You can use a 2-d data structure such as a range tree or binary-indexed tree to solve both kinds of range queries in O(log2 n). The total runtime will be O(n2 · log2 n).
You can get rid of one log factor using fractional cascading, but that is associated with a high constant factor. The runtime is then only one log-factor short of that for finding the longest common subsequence, which seems like a lower-bound for our problem.
Given two arrays A and B, each containing n non-negative numbers, remove a>0 elements from the end of A and b>0 elements from the end of B. Evaluate the cost of such an operation as X*Y where X is the sum of the a elements removed from A and Y the sum of the b elements removed from B. Keep doing this until both arrays are empty. The goal is to minimize the total cost.
Using dynamic programming and the fact that an optimal strategy will always take exactly one element from either A or B I can find an O(n^3) solution. Now I'm curious to know if there is an even faster solution to this problem?
EDIT: Stealing an example from #recursive in the comments:
A = [1,9,1] and B = [1, 9, 1]. Possible to do with a cost of 20. (1) *
(1 + 9) + (9 + 1) * (1)
Here's O(n^2). Let CostA(i, j) be the min cost of eliminating A[1..i], B[1..j] in such a way that the first removal takes only one element from B. Let CostB(i, j) be the min cost of eliminating A[1..i], B[1..j] in such a way that the first removal takes only one element from A. We have mutually recursive recurrences
CostA(i, j) = A[i] * B[j] + min(CostA(i - 1, j),
CostA(i - 1, j - 1),
CostB(i - 1, j - 1))
CostB(i, j) = A[i] * B[j] + min(CostB(i, j - 1),
CostA(i - 1, j - 1),
CostB(i - 1, j - 1))
with base cases
CostA(0, 0) = 0
CostA(>0, 0) = infinity
CostA(0, >0) = infinity
CostB(0, 0) = 0
CostB(>0, 0) = infinity
CostB(0, >0) = infinity.
The answer is min(CostA(n, n), CostB(n, n)).
I have been struggling through a dynamic programming exercise and I can't seem to get the hold of it. I'll write here the problem and also it's solution stating explicitly what I don't understand.
We are given 2 sequences u1,u2,...,un and d1,d2,...,dm and a matrix of dimensions n x m built of positive integers C=[cij]. A list of k pairs
((ui1, dj1),(ui2,dj2),...,(uik,djk)) is said to be non-intersecting if
i1 < 12 <..< ik and j1 < j2 <...< jk.
The "compatibility of a list" is said to be the compatibility of the sum of the pairs that it is made of, that is Ci1j1 + Ci2j2 + ... + Cikjk
Example :
Consider the matrix C = [Cij], so Cij = squared(i + j). Let i be
i = 1, 2, 3, j = 1, 2, 3, 4 and k = 2. Some lists of 2 non-intersecting pairs are these ((u1, d2),(u3, d3)) with a compatibility of 9 + 36 = 45,
((u2, d2),(u3, d4)), with compatibility 16 + 49 = 65, and ((u1, d1),(u2, d4)), with compatibility of 4 + 36 = 40. Some lists that are not non-intersecting are the following : ((u2, d2),(u3, d1)),((u1, d4),(u3, d3)),((u3, d2),(u2, d3))
Solution:
M(i, j, t) = maximum cost of t non-intersecting pairs taken from ui,...,un and dj,...dm
Recurrence equation :
M(i, j, t) = max {M(i + 1, j + 1, t − 1) + c(i, j), M(i, j + 1, t),M(i + 1, j, t).}
M(i, j, 0) = 0
M(i, j, t) = −∞, if t > min{n − i + 1, m − j + 1}
M(i, j, t) = 0, if i > n or j > m
I don't under the reccurrence very well and why do we assign −∞ to M(i, j, t) when t > min{n − i + 1, m − j + 1} but 0 when i > n or j > m
The solution is M(1, 1, k).
M(i, j, t) = max {M(i + 1, j + 1, t − 1) + c(i, j), M(i, j + 1, t),M(i + 1, j, t).}
= max
{
M(i+1, j+1, t-1) + c(i, j), <- we know the maximum cost of t-1
non-intersecting pairs taken from
i+1,...,n and j+1,...,m to which
we prepend the pair (i, j).
M(i, j+1, t), <- keep it at t elements and don't prepend anything,
and take the one containing elements from
i,...,n and j+1,...,m
M(i+1, j, t) <- same, but take elements from i+1,...,n and j,...,m
}
This covers all cases: either we prepend the current element and increase the length by 1 or we don't increase the length and take the maximum of the possibilities this (lack of) action entails. You might ask "but what about M(i+1,j+1,t)? that's also a valid possibility." It is, but it's covered by the two other cases: M(i+1,j,t) will check M(i+1,j+1,t) and return it if needed. You could add it yourself to the recurrence, it wouldn't be wrong, just redundant.
why do we assign −∞ to M(i, j, t) when t > min{n − i + 1, m − j + 1}
Because you cannot have a solution in that case. At step i, you can only pick n - i + 1 elements from the first sequence (because you already picked up to i). Same for j. If t > min{n - i + 1, m - j + 1}, then you will not be able to pick the needed number of elements from one of the lists, and you mark that with negative infinity.
but 0 when i > n or j > m
This is just to handle out of range errors. I'm not sure why they choose 0, I would choose negative infinity for this as well just for consistency, or just avoid it altogether by putting conditions in the implementation (if i + 1 >= n then ignore this branch, although you'll still need to return 0/-infinity if none of the branches are valid), but it doesn't really matter.
If you return 0 and the answer is negative, then you'll run into problems. Of course, for your problem, due to the way C is built, we cannot have a negative solution (because C contains squares of numbers, which are >= 0 always). So you could go with 0 instead of negative infinity in the first case as well.
Exercise: can you write a similar recurrence, but for which the solution is given by M(n, m, k)? Define it in words first, and then mathematically.
Given an array A with N elements, I want to find the sum of minimum elements in all the possible contiguous sub-sequences of A. I know if N is small we can look for all possible sub sequences but as N is upto 10^5 what can be best way to find this sum?
Example: Let N=3 and A[1,2,3] then ans is 10 as Possible contiguous sub sequences {(1),(2),(3),(1,2),(1,2,3),(2,3)} so Sum of minimum elements = 1 + 2 + 3 + 1 + 1 + 2 = 10
Let's fix one element(a[i]). We want to know the position of the rightmost element smaller than this one located to the left from i(L). We also need to know the position of the leftmost element smaller than this one located to the right from i(R).
If we know L and R, we should add (i - L) * (R - i) * a[i] to the answer.
It is possible to precompute L and R for all i in linear time using a stack. Pseudo code:
s = new Stack
L = new int[n]
fill(L, -1)
for i <- 0 ... n - 1:
while !s.isEmpty() && s.top().first > a[i]:
s.pop()
if !s.isEmpty():
L[i] = s.top().second
s.push(pair(a[i], i))
We can reverse the array and run the same algorithm to find R.
How to deal with equal elements? Let's assume that a[i] is a pair <a[i], i>. All elements are distinct now.
The time complexity is O(n).
Here is a full pseudo code(I assume that int can hold any integer value here, you should
choose a feasible type to avoid an overflow in a real code. I also assume that all elements are distinct):
int[] getLeftSmallerElementPositions(int[] a):
s = new Stack
L = new int[n]
fill(L, -1)
for i <- 0 ... n - 1:
while !s.isEmpty() && s.top().first > a[i]:
s.pop()
if !s.isEmpty():
L[i] = s.top().second
s.push(pair(a[i], i))
return L
int[] getRightSmallerElementPositions(int[] a):
R = getLeftSmallerElementPositions(reversed(a))
for i <- 0 ... n - 1:
R[i] = n - 1 - R[i]
return reversed(R)
int findSum(int[] a):
L = getLeftSmallerElementPositions(a)
R = getRightSmallerElementPositions(a)
int res = 0
for i <- 0 ... n - 1:
res += (i - L[i]) * (R[i] - i) * a[i]
return res
If the list is sorted, you can consider all subsets for size 1, then 2, then 3, to N. The algorithm is initially somewhat inefficient, but an optimized version is below. Here's some pseudocode.
let A = {1, 2, 3}
let total_sum = 0
for set_size <- 1 to N
total_sum += sum(A[1:N-(set_size-1)])
First, sets with one element:{{1}, {2}, {3}}: sum each of the elements.
Then, sets of two element {{1, 2}, {2, 3}}: sum each element but the last.
Then, sets of three elements {{1, 2, 3}}: sum each element but the last two.
But this algorithm is inefficient. To optimize to O(n), multiply each ith element by N-i and sum (indexing from zero here). The intuition is that the first element is the minimum of N sets, the second element is the minimum of N-1 sets, etc.
I know it's not a python question, but sometimes code helps:
A = [1, 2, 3]
# This is [3, 2, 1]
scale = range(len(A), 0, -1)
# Take the element-wise product of the vectors, and sum
sum(a*b for (a,b) in zip(A, scale))
# Or just use the dot product
np.dot(A, scale)
I'm trying to come up with fast algorithm to find result of operation, where
L - is symmetric n x n matrix with real numbers.
A - is sparse n x m matrix, m < n. Each row has one and only one non-zero element, and it's equal to 1. It's also guaranteed that every column has at most two non-zero elements.
I come up with one algorithm, but I feel like there should be something faster than this.
Let's represent every column of A as pair of row numbers with non-zero elements. If a column has only one non-zero element, its row number listed twice. E.g. for the following matrix
Such representation would be
column 0: [0, 2]; column 1: [1, 3]; column 2: [4, 4]
Or we can list it as a single array: A = [0, 2, 1, 3, 4, 4]; Now, can be calculated as:
for (i = 0; i < A.length; i += 2):
if A[i] != A[i + 1]:
# sum of two column vectors, i/2-th column of L'
L'[i/2] = L[A[i]] + L[A[i + 1]]
else:
L'[i/2] = L[A[i]]
To calculate we do it one more time:
for (i = 0; i < A.length; i += 2):
if A[i] != A[i + 1]:
# sum of two row vectors, i/2-th row of L''
L''[i/2] = L'[A[i]] + L'[A[i + 1]]
else:
L''[i/2] = L'[A[i]]
The time complexity of such approach is O(mn + mn), and space complexity (to get final result) is O(nn). I'm wondering if it's possible to improve it to O(mm) in terms of space and/or performance?
The second loop combines at most 2m rows of L', so if m is much smaller than n there will be several rows of L' that are never used.
One way to avoid calculating and storing these unused entries is to change your first loop into a function and only calculate the individual elements of L' as they are needed.
def L'(row,col):
i=col*2
if A[i] != A[i + 1]:
# sum of two column vectors, i/2-th column of L'
return L[row][A[i]] + L[row][A[i + 1]]
else:
return L[row][A[i]]
for (i = 0; i < A.length; i += 2):
if A[i] != A[i + 1]:
for (k=0;k<m;k++):
L''[i/2][k] = L'(A[i],k) + L'(A[i + 1],k)
else:
for (k=0;k<m;k++):
L''[i/2][k] = L'(A[i],k)
This should then have space and complexity O(m*m)
The operation Transpose(A) * L works as follows:
For each column of A we see:
column 1 has `1` in row 1 and 3
column 2 has `1` in row 2 and 4
column 3 has `1` in row 5
The output matrix B = Transpose(A) * L has three rows which are equal to:
Row(B, 1) = Row(A, 1) + Row(A, 3)
Row(B, 2) = Row(A, 2) + Row(A, 4)
Row(B, 3) = Row(A, 5)
If we multiply C = B * A:
Column(C, 1) = Column(B, 1) + Column(B, 3)
Column(C, 2) = Column(B, 2) + Column(B, 4)
Column(C, 3) = Column(B, 5)
If you follow through this in a algorithmic way, you should achieve something very similar to what Peter de Rivaz has suggested.
The time complexity of your algorithm is O(n^2), not O(m*n). The rows and columns of L have length n, and the A array has length 2n.
If a[k] is the column where row k of A has a 1, then you can write:
A[k,i] = δ(a[k],i)
and the product, P = A^T*L*A is:
P[i,j] = Σ(k,l) A^T[i,k]*L[k,l]*A[l,j]
= Σ(k,l) A[k,i]*L[k,l]*A[l,j]
= Σ(k,l) δ(a[k],i)*L[k,l]*δ(a[l],j)
If we turn this around and look at what happens to the elements of L, we see that L[k,l] is added to P[a[k],a[l]], and it's easy to get O(m^2) space complexity using O(n^2) time complexity.
Because a[k] is defined for all k=0..n-1, we know that every element of L must appear somewhere in the product. Because there are O(n^2) distinct elements in L, you can't do better than O(n^2) time complexity.