Dynamic programming question - algorithm

A circus is designing a tower routine consisting of people standing atop one another’s
shoulders. For practical and aesthetic reasons, each person must be both shorter and lighter than the person below him or her. Given the heights and weights of each person in the circus, write a method to compute the largest possible number of people
in such a tower.
EXAMPLE:
Input (ht, wt): (65, 100) (70, 150) (56, 90) (75, 190) (60, 95) (68, 110)
Output: The longest tower is length 6 and includes from top to bottom: (56, 90) (60,95) (65,100) (68,110) (70,150) (75,190)
Someone suggested me the following:
It can be done as follows:
Sort the input in decreasing order of weight and find the longest decreasing sequence of hight.
Sort the input in decreasing order of hight and find the longest decreasing sequence of weight.
Take max of 1 and 2.
I dont understand why we need to do both steps 1 and 2. Cant we just do 1 and find the answer. IF not , please give example in which doing only step 1 does not give answer?

Result of 1 and 2 has to be same. It's not possible that one of them is shorter, because in a solution elements are descending both in height and weight so if it satisfies 1 or 2 it will satisfy the other as well, If it would be shorter it wouldn't be the longest.

You might need to say something about the weights & heights all being unique.
Otherwise, if
A is (10, 10) // (w, h)
B is ( 9, 10)
C is ( 9, 8)
Then neither method gets the correct answer!
C obviously can stand on A's shoulders.
Edit:
Neither method is good enough!
Example with all weights & heights unique:
A : (12, 12)
B : (11, 8)
C : (10, 9)
D : ( 9, 10)
E : ( 8, 11)
F : ( 7, 7)
Both methods give an answer of 2, however the tower can be at least of height 3 with several combinations:
A on the bottom,
then any of B, C, D, or E,
then F on top.
I think stricter rules on the input data are needed to make this problem solvable by the given methods.

You're absolutely correct. Doing just one direction is enough.
A proof is easy by using the maximum property of the subsequence. We assume one side (say the left) of values is ordered, and take the longest descending subsequence of the right. We now perform the other operation, order the right and take the subsequence from the left.
If we arrive at a list that is either shorter or longer than the first one we found we have reached a contradiction, since that subsequence was ordered in the very same relative order in the first operation, and thus we could have found a longer descending subsequence, in contradiction to the assumption that the one we took was maximal. Similarly if it's shorter then the argument is symmetrical.
We conclude that finding the maximum on just one side will be the same as the maximum of the reverse ordered operation.
Worth noting that I haven't proven that this is a solution to the problem, just that the one-sided algorithm is equivalent to the two-sided version. Although the proof that this is correct is almost identical, assume that there exists a longer solution and it contradicts the maximalness of the subsequence. That proves that there is nothing longer, and it's trivial to see that every solution the algorithm produces is a valid solution. Which means the algorithm's result is both >= the solution and <= the solution, therefore it is the solution.

It doesn't make any difference. And it is unnecessary to pre-sort as you end up with the same graph to search.

As far as I can see, this is the same question as Box stacking problem:
Also: http://people.csail.mit.edu/bdean/6.046/dp/

Related

How does the recursion unfolds in coin changing algorithm?

I know there are tonnes of editorials and blogs explaining this but there is one common point where i am getting stuck.
Considering the recursion given below:
coin_change(coins,i,N) = coin_change(coins,i-1,N) + coin_change(coins,i-1,N-val[i])
Now this seems pretty straightforward which i think says that either we exclude the coin or we include it and solve the problem for remaining sum.
But my doubt is since there is infinite supply of coins, we can take as many coins as possible to achieve the sum, so how are we incorporating that thing in the recursive solution?
Also i am not able to understand the base cases for this problem!
This creates a binary tree, where the right branch searches subtracting the same coin again and again and the left branch searches all the other coins.
Take the simple case of N = 3 and coins = {1, 2}:
The right hand branch would be:
{1,2}: 1->1->1 (1,1,1)
{2}: ->2 (1,2)
The left hand branch would be:
{2}: 2->X (No solution)
Would give the same result if 2 was the first coin:
Right hand branch:
{2,1}: 2->X (No solution)
{1} ->1 (2,1)
Left hand branch:
{1}: 1->1->1 (1,1,1)
Note 1: you shouldn't have -1 on the second call:
coin_change(coins,i,N) = coin_change(coins,i-1,N) + coin_change(coins,i,N-val[i])
Note 2: this isn't dynamic programming.
If there is infinite supply of coins, then given condition allows to exclude whole nominal of coins. For example, no more nickels in solution. val array could look as [1,5,10,25...]
Note that problem with limited number of coins is slightly more complex - we have to organize array with repeated values [1,1,1,5,5,10,10,10,10,10,...] or use array of counters for every coin nominal [1:3; 5:0; 10:12; ...].

Algorithm to find first sequence of integers that sum to certain value

I have a list of numbers and I have a sum value. For instance,
list = [1, 2, 3, 5, 7, 11, 10, 23, 24, 54, 79 ]
sum = 20
I would like to generate a sequence of numbers taken from that list, such that the sequence sums up to that target. In order to help achieve this, the sequence can be of any length and repetition is allowed.
result = [2, 3, 5, 10] ,or result = [1, 1, 2, 3, 3, 5, 5] ,or result = [10, 10]
I've been doing a lot of research into this problem and have found the subset sum problem to be of interest. My problem is, in a few ways, similar to the subset sum problem in that I would like to find a subset of numbers that produces the targeted sum.
However, unlike the subset sum problem which finds all sets of numbers that sum up to the target (and so runs in exponential time if brute forcing), I only want to find one set of numbers. I want to find the first set that gives me the sum. So, in a certain sense, speed is a factor.
Additionally, I would like there to be some degree of randomness (or pseudo-randomness) to the algorithm. That is, should I run the algorithm using the same list and sum multiple times, I should get a different set of numbers each time.
What would be the best algorithm to achieve this?
Additional Notes:
What I've achieved so far is using a naive method where I cycle through the list adding it to every combination of values. This obviously takes a long time and I'm currently not feeling too happy about it. I'm hoping there is a better way to do this!
If there is no sequence that gives me the exact sum, I'm satisfied with a sequence that gives me a sum that is as close as possible to the targeted sum.
As others said, this is a NP-problem.
However, this doesn't mean small improvements aren't possible:
Is 1 in the list? [1,1,1,1...] is the solution. O(1) in a sorted list
Remove list element bigger than the target sum. O(n)
Is there any list element x with (x%sum)==0 ? Again, easy solution. O(n)
Are there any list elements x,y with (x%y)==0 ? Remove x. O(n^2)
(maybe even: Are there any list elements x,y,z with (x%y)==z or (x+y)==z ? Remove x. O(n^3))
Before using the full recursion, try if you can get the sum
just with the smallest even and smallest odd number.
...
Subset Sum problem isn't about finding all subsets, but rather about determining if there is some subset. It is a decision problem. All problems in NP are like this. And even this simpler problem is NP-complete.
This means that if you want an exact answer (the subset must sum exactly some value) you won't be able to do much better than the any subset sum algorithm (it is exponential unless P=NP).
I would attempt to reduce the problem to a brute-force search of a smaller set.
Sort the list smallest to largest.
Keep a sum and result list.
Repeat {
Draw randomly from the subset of list less than target - sum.
Increment sum by drawn value, add drawn value to result list.
} until list[0] > sum or sum == 0
If sum != 0, brute force search for small combinations from list that match the difference between sum and small combinations of result.
This approach may fail to find valid solutions, even if they exist. It can, however, quickly find a solution or quickly fail before having to resort to a slower brute force approach using the entire set at a greater depth.
This is a greedy approach to the problem:
Without 'randomness':
Obtain the single largest number in the set that is smaller than your desired sum- we'll name it X. Given it's ordered, at best it's O(1), and O(N) at worst if the sum is 2.
As you can repeat the value- say c times, do so as many times until you get closest to the sum, but be careful! Create a range of values- essentially now you'll be finding another sum! You'll now be find numbers that add up to R = (sum - X * c). So find the largest number smaller than R. Check if R - (number you just found) = 0 or if any [R - (number you just found)] % (smaller #s) == 0.
If it becomes R > 0, make partial sums of the smaller numbers less than R (this will not be more than 5 ~ 10 computations because of the nature of this algorithm). See if these would then satisfy it.
If that step makes R < 0, remove one X and start the process again.
With 'randomness':
Just get X randomly! :-)
Note: This would work best if you have a few single digit numbers.

Put k stones on a n * m grid, to maximize the number of rectangles for which there is one stone in each corner

Put k stones on a n * m grid, each stone should be on an intersection point of the lines of grid.Try to find a way to put the stones, in order to maximize the number of rectangles for which there is one stone in each corner. Output the number.
for example, if k <= 3, the answer is 0, meaning no such rectangle; if k is 4 and n, m >= 2, the answer is 1; more examples:
(n, m, k, answer): (3, 3, 8, 5), (4, 5, 13, 18), (7, 14, 86, 1398)
k is between 0 and n * m.
n, m are positive integers less than 30000
ps:This is actually a problem in Microsoft-Beauty-of-Programming qualification round(But you may not be able to find it since it is held in China and I translate it to English myself.)
pss:I have made some progress. It can be proved that to get the answer, searching through all possible Ferrers diagrams is enough, but the complexity is exponential with regard to k.
EDIT: (by Dukeling)
A visualization of (3, 3, 8, 5), with the rectangles indicated in different colours.
As you noticed, it's actually a (n-1) * (m-1) grid, there's another interpretation using a n * m grid where the stones are placed inside the cells, but then you'll need to add an additional constraint that rectangles can't be width / height 1.
From a programming perspective this suggests a search that takes advantage of the symmetries of the rectangle to reduce search space. What follows is something of an extended hint.
As the OP points out, a naive implementation would check all possible k-subsets of nodes, a size of C(nm,k).
The amount of search space reduction depends on how symmetries are exploited. The square has symmetries of reflection and rotation, so for n=m there's an 8-fold symmetry group. If say n < m, then the lesser amount of symmetry gives a 4-fold group.
A typical approach is to organize the possible k-subsets by a lexicographic ordering, so that a potential configuration is skipped when it's equivalent to one of earlier appearance in that ordering.
But there are additional "wrap-around" symmetries to be exploited. Suppose the last row of the grid is moved to the top (along with any assignment of stones to its nodes). This transformation preserves the count of the 4-stone rectangles (though the exact sizes of those rectangles will differ).
Indeed transposing two rows or two columns preserves the counts of 4-stone rectangles. Once you have that insight, can you see how to parameterize the search space more efficiently?
Added: Even though it's more of a math insight than programming, consider the number of 4-stone rectangles provided by a "full subrectangle", say r x c if rc < k. Consider the incremental number of extra rectangles provided by one more stone; by two more stones.

Revisit: 2D Array Sorted Along X and Y Axis

So, this is a common interview question. There's already a topic up, which I have read, but it's dead, and no answer was ever accepted. On top of that, my interests lie in a slightly more constrained form of the question, with a couple practical applications.
Given a two dimensional array such that:
Elements are unique.
Elements are sorted along the x-axis and the y-axis.
Neither sort predominates, so neither sort is a secondary sorting parameter.
As a result, the diagonal is also sorted.
All of the sorts can be thought of as moving in the same direction. That is to say that they are all ascending, or that they are all descending.
Technically, I think as long as you have a >/=/< comparator, any total ordering should work.
Elements are numeric types, with a single-cycle comparator.
Thus, memory operations are the dominating factor in a big-O analysis.
How do you find an element? Only worst case analysis matters.
Solutions I am aware of:
A variety of approaches that are:
O(nlog(n)), where you approach each row separately.
O(nlog(n)) with strong best and average performance.
One that is O(n+m):
Start in a non-extreme corner, which we will assume is the bottom right.
Let the target be J. Cur Pos is M.
If M is greater than J, move left.
If M is less than J, move up.
If you can do neither, you are done, and J is not present.
If M is equal to J, you are done.
Originally found elsewhere, most recently stolen from here.
And I believe I've seen one with a worst-case O(n+m) but a optimal case of nearly O(log(n)).
What I am curious about:
Right now, I have proved to my satisfaction that naive partitioning attack always devolves to nlog(n). Partitioning attacks in general appear to have a optimal worst-case of O(n+m), and most do not terminate early in cases of absence. I was also wondering, as a result, if an interpolation probe might not be better than a binary probe, and thus it occurred to me that one might think of this as a set intersection problem with a weak interaction between sets. My mind cast immediately towards Baeza-Yates intersection, but I haven't had time to draft an adaptation of that approach. However, given my suspicions that optimality of a O(N+M) worst case is provable, I thought I'd just go ahead and ask here, to see if anyone could bash together a counter-argument, or pull together a recurrence relation for interpolation search.
Here's a proof that it has to be at least Omega(min(n,m)). Let n >= m. Then consider the matrix which has all 0s at (i,j) where i+j < m, all 2s where i+j >= m, except for a single (i,j) with i+j = m which has a 1. This is a valid input matrix, and there are m possible placements for the 1. No query into the array (other than the actual location of the 1) can distinguish among those m possible placements. So you'll have to check all m locations in the worst case, and at least m/2 expected locations for any randomized algorithm.
One of your assumptions was that matrix elements have to be unique, and I didn't do that. It is easy to fix, however, because you just pick a big number X=n*m, replace all 0s with unique numbers less than X, all 2s with unique numbers greater than X, and 1 with X.
And because it is also Omega(lg n) (counting argument), it is Omega(m + lg n) where n>=m.
An optimal O(m+n) solution is to start at the top-left corner, that has minimal value. Move diagonally downwards to the right until you hit an element whose value >= value of the given element. If the element's value is equal to that of the given element, return found as true.
Otherwise, from here we can proceed in two ways.
Strategy 1:
Move up in the column and search for the given element until we reach the end. If found, return found as true
Move left in the row and search for the given element until we reach the end. If found, return found as true
return found as false
Strategy 2:
Let i denote the row index and j denote the column index of the diagonal element we have stopped at. (Here, we have i = j, BTW). Let k = 1.
Repeat the below steps until i-k >= 0
Search if a[i-k][j] is equal to the given element. if yes, return found as true.
Search if a[i][j-k] is equal to the given element. if yes, return found as true.
Increment k
1 2 4 5 6
2 3 5 7 8
4 6 8 9 10
5 8 9 10 11

Algorithm to find minimum number of weightings required to find defective ball from a set of n balls

Okay here is a puzzle I come across a lot of times-
Given a set of 12 balls , one of which is defective (it weighs either less or more) . You are allow to weigh 3 times to find the defective and also tell which weighs less or more.
The solution to this problem exists, but I want to know whether we can algorithmically determine if given a set of 'n' balls what is the minimum number of times you would need to use a beam balance to determine which one is defective and how(lighter or heavier).
A wonderful algorithm by Jack Wert can be found here
http://www.cut-the-knot.org/blue/OddCoinProblems.shtml
(as described for the case n is of the form (3^k-3)/2, but it is generalizable to other n, see the writeup below)
A shorter version and probably more readable version of that is here
http://www.cut-the-knot.org/blue/OddCoinProblemsShort.shtml
For n of the form (3^k-3)/2, the above solution applies perfectly and the minimum number of weighings required is k.
In other cases...
Adapting Jack Wert's algorithm for all n.
In order to modify the above algorithm for all n, you can try the following (I haven't tried proving the correctness, though):
First check if n is of the from (3^k-3)/2. If it is, apply above algorithm.
If not,
If n = 3t (i.e. n is a multiple of 3), you find the least m > n such that m is of the form (3^k-3)/2. The number of weighings required will be k. Now form the groups 1, 3, 3^2, ..., 3^(k-2), Z, where 3^(k-2) < Z < 3^(k-1) and repeat the algorithm from Jack's solution.
Note: We would also need to generalize the method A (the case when we know if the coin is heavier of lighter), for arbitrary Z.
If n = 3t+1, try to solve for 3t (keeping one ball aside). If you don't find the odd ball among 3t, the one you kept aside is defective.
If n = 3t+2, form the groups for 3t+3, but have one group not have the one ball group. If you come to the stage when you have to rotate the one ball group, you know the defective ball is one of two balls and you can then weigh one of those two balls against one of the known good balls (from among the other 3t).
Trichotomy ! :)
Explanation :
Given a set of n balls, subdivide it in 3 sets A, B and C of n/3 balls.
Compare A and B. If equal, then the defective ball is in C.
etc.
So, your minimum number of times is the number of times you can divide n by three (sorry, i do not know the english word for that).
You could use a general planning algorithm: http://www.inf.ed.ac.uk/teaching/courses/plan/

Resources