Dynamic Programming - Jumping jacks - algorithm

Can some one help in solving the below problem using DP technique.
No need of code. Idea should be enough.
Marvel is coming up with a new superhero named Jumping Jack. The co-creator of this superhero is a mathematician, and he adds a mathematical touch to the character's powers.
So, one of Jumping Jack's most prominent powers is jumping distances. But, this superpower comes with certain restrictions.
Jumping Jack can only jump —
To the number that is one kilometre lesser than the current distance. For example, if he is 12 km away from the destination, he won't be able to jump directly to it since he can only jump to a location 11 km away.
To a distance that is half the current distance. For example, if Jumping Jack is 12 km away from the destination, again, he won't be able to jump directly to it since he can only jump to a location 6 km away.
To a distance that is ⅓rd the current distance. For example, if Jumping Jack is 12 km away from the destination, once more, he won't be able to jump directly to it since he can only jump to a location 4 km away.
So, you need to help the superhero develop an algorithm to reach the destination in the minimum number of steps. The destination is defined as the place where the distance becomes 1. Jumping Jack should cover the last 1 km running! Also, he can only jump to a destination that is an integer distance away from the main destination. For example, if he is at 10 km, by jumping 1/3rd the distance, he cannot reach 10/3rd the distance. He has to either jump to 5 or 9.
So, you have to find the minimum number of jumps required to reach a destination. For instance, if the destination is 10 km away, there are two ways to reach it:
10 -> 5 -> 4 -> 2 -> 1 (four jumps)
10 -> 9 -> 3 -> 1 (three jumps)
The minimum of these is three, so the superhero takes a minimum of three jumps to reach the point.

You should keep the following 2 points in mind for solving all the Dynamic programming problems:
Optimal Substructure (to find the minimum number of jumps)
Overlapping subproblems (If you encounter the same subproblem again, don't solve it, rather used the already computed result - yes, you'll have to store the computed result of sub-problems for future reference)
Always try to make a recursive solution to the problem at hand (now don't directly go ahead and look at the recursive solution, rather first try it yourself):
calCulateMinJumps(int currentDistance) {
if(currentDistance == 1) {
// return jumps - you don't need to recurse here
} else {
// find at what all places you can jump
jumps1 = calculateMinJumps(n-1) + 1
if(currentDistance % 2 == 0)
jumps2 = calculateMinJumps(n/2) + 1
if(currentDistance % 3 == 0)
jumps3 = calculateMinJumps(n/3) + 1
return minimum(jumps1, jumps2, jumps3) // takes jump2 and jump3 only if they are valid
}
}
Now you know that we have devised a recursive solution. The next step is to go and store the solution in an array so that you can use it in future and avoid re-computation. You can simply take a 1-D integer array and keep on storing it.
Keep in mind that if you go by top-down approach - it will be called memoization, and if you go by bottom-up approach - it will be called Dynamic programming. Have a look at this to see the exact difference between the two approaches.
Once you have a recursive solution in your mind, you can now think of constructing a bottom-up solution, or a top-down solution.
In Bottom-up solution strategy - you fill out the base cases first (Jumping Jack should cover the last 1 km running!) and then build upon it to reach to the final required solution.
Now, I'm not giving you the complete strategy, as it will be a task for you to carry out. And you will indeed find the solution. :) - As requested by you - Idea should be enough.

Firstly, think about this coin changing problem may help you understand yours, which are much the same:
Coin change - DP
Secondly, usually if you know that your problem has a DP solution, you can do 4 steps to solve it. Of cause you can ommit one or all of the first 3 steps.
Find a backtrack solution.(omitted here)
Find the recursion formula for your problem, based on the backtrack solution. (describe later)
Write a recursion code based on the recursion formula.(Omitted)
Write a iterating code based on step 3.(Omitted)
Finaly, for your question, the formula is not hard to figure out:
minStepFor(distance_N)=Math.min(minStepFor(distance_N-1)+1),
minStepFor(distance_N/2)+1,
minStepFor(distance_N/3)+1)
Just imagine jack is standing at the distance N point, and he has at most three options for his first go: go to N-1 point, or N/2 point, or N/3 point(if N/2 or N/3 is not integer, his choice will be reduced).
For each of his choice, the minimum steps is minStepFor(left distance)+1, since he has made 1 move, and surely he will try to make a minimum steps in his left moving. And the left distance for each choice is distance_N-1,distance_N/2 and distance_N/3.
So that's the way to understand the formula. With it it is not hard to write a recursion solution.

Consider f[1]=0 as the number of jumps required when JumpingJack is 1km away is none.
Using this base value solve F[2]...f[n] in below manner
for(int i=2; i<=n; i++) {
if(i%2==0 && i%3==0) {
f[i] = Math.min(Math.min(f[i-1]+1, f[i/2]+1), f[i/3] + 1);
}
if(i%2==0) {
f[i] = Math.min(f[i-1]+1, f[i/2]+1);
}else if(i%3==0) {
f[i] = Math.min(f[i-1]+1, f[i/3] + 1);
}else{
f[i] = f[i-1]+1;
}
}
return f[n];
You don't need to recursively solve the subproblem more than once!

Related

Finding a door in an infinitly long wall

Let's say you stand in front of a massive wall.
The wall is infinitly long to your right and left side. You know that there is a door somewhere and you try to find it to reach the other side.
Sadly, it is night and you can only feel the part of the wall in front of you.
You don't know how far away the door is or what direction you have to go but you can count your steps, starting from your startpoint.
How can you solve this problem?
The naive approach would be to start at the startpoint and go +1 to the right, check and if no door is found, go to the start and go -1 and check again. If there is still no door you would have to go to the start and check +2 to the right and so on....
This would result in O(n^2) steps to find the door (Where n is the number of steps from the startpoint to the door).
Is there a better way? Maybe even in O(n) steps?
I don't even exactly know what tags I should ask this so feel free to add some if you think they fit.
The problem is that you don't know which way to go, so whatever solution you come up with, you have to go back to the origin and start going the other way. Furthermore you can never rule out either of the directions until after you've found the door making you go back to origin any number of times with any algorithm with sufficiently large n (where I assume n is the distance of the door from the origin).
That means we want to go back as little as possible, but we still will have to. The solution is to not increment the step by just one, but travel twice the distance.
For simplicity without hurting the asymptotic complexity, we will travel distance d to some point, then come back, travel the same distance to the other direction and finally come back again. This only gives us constant 4 for our complexity, so we can disregard it later. Anyways when I will talk about an iteration, it means all of these 4 routes even though you will have found the door before completing all of them in the last iteration.
So in the first step you can travel to tile 2, in second to tile 4, then 8, 16, etc.
You will find the door in the k-th iteration where 2^k >= n > 2^(k-1), which means k >= log(n) > k-1. For simplicity we can assume that n is a power of 2, because for the computation it doesn't matter if n is for example 33 or 64 (or minus any of those), we will find all of these in the same iteration. So we can write k = log(n).
You are now summing just part of geometric sequence, so after k-th iteration you will have traveled total of 4 * 2*(2^k - 1)/(2 - 1) = 8 * (2^log(n) - 1) = 8 * (n - 1) = 8n - 8 = O(n).

scheduling n people with given time of travel

this is a puzzle but i think it could be a classical algorithm which i am unaware of :
There are n people at the bottom of a mountain, and everyone wants to go up, then down the mountain. Person i takes u[i] time to climb this mountain, and d[i] time to descend it.
However, at same given time atmost 1 person can climb , and .atmost 1 person can descend the mountain. Find the least time to travel up and back down the mountain.
Update 1 :
well i tried with few examples and found that it's not reducible to sorting , or getting the fastest climbers first or vice versa . I think to get optimal solution we may have to try out all possible solutions , so seems to be NP complete.
My initial guess: (WRONG)
The solution i thought is greedy : sort n people by start time in ascending order. Then up jth person up and kth down where u[j]<= d[k] and d[k] is minimum from all k persons on top of mountain. I am not able to prove correctness of this .
Any other idea how to approach ?
A hint would suffice.
Try to think in the following manner: if the people are not sorted in ascending order of time it takes them to climb the mountain than what happens if you find a pair of adjacent people that are not in the correct order(i.e. first one climbs longer than second one) and swap them. Is it possible that the total time increases?
I think it is incorrect. Consider
u = [2,3]
d = [1,3]
Your algorithm gives ordering 0,1 whereas it should be 1,0.
I would suggest another greedy approach:
Create ordering list and add first person.
For current ordering keep track of two values:
mU - time of last person on the mountain - time of the end
mD - time of earliest time of first descending
From people who are not ordered choose the one which minimises abs(mD - d) and abs(mU - u). Then if abs(mD - d) < abs(mU - u) he should go at the beginning of ordering. Otherwise he goes at the end.
Some tweak may still be needed here, but this approach should minimise losses from cases like the one given in the example.
The following solution will only work with n <= 24.
This solution will require dynamic programming and bit-mask technique knowledge to be understood.
Observation: we can easily observe that the optimal total climb up time is fixed, which is equalled to the total climb up time of n people.
For the base case, if n = 1, the solution is obvious.
For n = 2, the solution is simple, just scan through all 4 possibilities and calculate the minimum down time.
For n = 3, we can see that this case will be equal to the case when one person climb up first, followed by two.
And the two person minimum down time can be easily pre-calculated. More important, this two person then can be treated as one person with up time is the total up time of the two, and down time is the minimum down time.
Storing all result for minimum down time for cases from n = 0 to n = 3 in array called 'dp', using bit-mask technique, we represent the state for 3 person as index 3 = 111b, so the result for case n = 3 will be:
for(int i = 0; i < 3; i++){
dp[3] = min(dp[(1<<i)] + dp[3^(1<<i)],dp[3]);
}
For n = 4... 24, the solution will be similar to case n = 3.
Note: The actual formula is not just simple as the code for case n = 3(and it requires similar approach to solve as case n = 2), but will be very similar,
Your approach looks sensible, but it may be over-simplified, could you describe it more precisely here?
From your description, I can't make out whether you are sorting or something else; these are the heuristics that I figured you are using:
Get the fastest climbers first, so the start using the Down path
asap.
Ensure there is always people at the top of the mountain, so
when the Down path becomes available, a person starts descending
immediately.The way you do that is to select first those people who
climb fast and descend slowly.
What if the fastest climber is also the fastest descender? That would leave the Down path idle until the second climber gets to the top, how does your algorithm ensures that this the best order?. I'm not sure that the problem reduces to a Sorting problem, it looks more like a knapsack or scheduling type.

Generic solution to towers of Hanoi with variable number of poles?

Given D discs, P poles, and the initial starting positions for the disks, and the required final destination for the poles, how can we write a generic solution to the problem?
For example,
Given D=6 and P=4, and the initial starting position looks like this:
5 1
6 2 4 3
Where the number represents the disk's radius, the poles are numbered 1-4 left-right, and we want to stack all the disks on pole 1.
How do we choose the next move?
The solution is (worked out by hand):
3 1
4 3
4 1
2 1
3 1
(format: <from-pole> <to-pole>)
The first move is obvious, move the "4" on top of the "5" because that its required position in the final solution.
Next, we probably want to move the next largest number, which would be the "3". But first we have to unbury it, which means we should move the "1" next. But how do we decide where to place it?
That's as far as I've gotten. I could write a recursive algorithm that tries all possible places, but I'm not sure if that's optimal.
We can't.
More precisely, as http://en.wikipedia.org/wiki/Tower_of_Hanoi#Four_pegs_and_beyond says, for 4+ pegs, proving what the optimal solution is is an open problem. There is a known very good algorithm, that is widely believed to be optimal, for the simple case where the pile of disks is on one peg and you want to transfer the whole pile to another. However we do not have an algorithm, or even a known heuristic, for an arbitrary starting position.
If we did have a proposed algorithm, then the open problem would presumably be much easier.

Best way to search for a saturation value in a sorted list

A question from Math Battle.
This particular question was also asked to me in one of my job interviews.
" A monkey has two coconuts. It is fooling around by throwing coconut down from the balconies
of M-storey building. The monkey wants to know the lowest floor when coconut is broken.
What is the minimal number of attempts needed to establish that fact? "
Conditions: if a coconut is broken, you cannot reuse the same. You are left with only with the other coconut
Possible approaches/strategies I can think of are
Binary break ups & once you find the floor on which the coconut breaks use upcounting from the last found Binary break up lower index.
Window/Slices of smaller sets of floors & use binary break up within the Window/Slice
(but on the down side this would require a Slicing algorithm of it's own.)
Wondering if there are any other ways to do this.
Interview questions like this are designed to see how you think. So I would probably mention a O(N^0.5) solution as above, but also I would give the following discussion...
Since the coconuts may have internal cracking over time, the results may not be so consistent to a O(N^0.5) solution. Although the O(N^0.5) solution is efficient, it is not entirely reliable.
I would recommend a linear O(N) solution with the first coconut, and then verify the result with the second coconut. Where N is the number of floors in the building. So for the first coconut you try the 1st floor, then the 2nd, then the 3rd, ...
Assuming both coconuts are built structurally exactly the same and are dropped on the exact same angle, then you can throw the second coconut directly on the floor that the first one broke. Call this coconut breaking floor B.
For coconut #2, you don't need to test on 1..B-1 because you already know that the first cocounut didn't break on floor B-1, B-2, ... 1. So you only need to try it on B.
If the 2nd coconut breaks on B, then you know that B is the floor in question. If it doesn't break you can deduce that there were internal cracking and degradation of the coconut over time and that the test is flawed to begin with. You need more coconuts.
Given that building sizes are pretty limited, the extra confidence in your solution is worth the O(N) solution.
As #Rafał Dowgird mentioned, the solution also depends on whether the monkey in question is an African monkey or a European monkey. It is common knowledge that African monkeys throw with a much greater force. Hence making the breaking floor B only accurate with a variance of +/- 2 floors.
To guarantee that the monkey doesn't get tired from all those stairs, it would also be advisable to attach a string to the first coconut. That way you don't need to do 1+2+..+B = B*(B+1)/2 flights of stairs for the first coconut. You would only need to do exactly B flights of stairs.
It may seem that the number of flights of stairs is not relevant to this problem, but if the monkey gets tired out in the first place, we may never come to a solution. This gives new considerations for the halting problem.
We are also making the assumption that the building resides on earth and the gravity is set at 9.8m/s^2. We'll also assume that no gravitation waves exist.
A binary search is not the answer, because you only get one chance to over-estimate. Binary search requires log m maximum over-estimations.
This is a two phase approach. The first is to iterate over the floors with relatively big steps. After the first coconut breaks, the second phase is to try each floor starting after the last safe floor.
The big steps are roughly sqrt(m), but they are bigger early, and smaller later because if the first coconut breaks early, you can afford more iterations in the second phase.
StepSize = (minimum s such that s * (s + 1) / 2 >= m)
CurrentFloor = 0
While no coconuts broken {
CurrentFloor += StepSize
StepSize -= 1
Drop coconut from CurrentFloor
}
CurrentFloor -= StepSize + 1
While one remains coconut unbroken {
CurrentFloor += 1
Drop remaining coconut from CurrentFloor
}
// CurrentFloor is now set to the lowest floor that will break the coconut,
// using no more total drops than the original value of StepSize
The best solution I know is 2*sqrt(n). Drop the first coconut from sqrt(n), 2*sqrt(n),... up to n (or until it breaks). Then drop the second one from the last known "safe" point, in one floor increments until it breaks. Both stages take at most sqrt(n) throws.
Edit: You can improve the constant within O(sqrt(n)), see comment by recursive. I think that the first step should be around sqrt(2*n) and decrease by 1 with each throw, so that the last step (if the breaking height is actually n) is exactly 1. Details to be figured out by readers :)
Since it's an interview question, consider
The expensive operation is the monkey going up and down the stairs, not tossing the coconut. Thinking about it this way, the 'linear' approach is actually N2.
The energy imparted to the coconut by falling is roughly proportional to the height of the drop. If the shell is broken after absorbing some amount of energy in ALL of it's falls ...
Tough interview question. It took me several days.
I believe the # of tries is 1.5 times SQRT of # of floors. (For 100 floors and 2 coco it is 15)
We want to minimize the size of each try and the # of tries, using both together to cover all possible floors. In such cases a sqroot turns out to be a good starting point, but we vary the size of each try and average around the sqroot.
This way we have the best of both worlds : Having the size of each try evenly distributed around the sqroot gives us the best results. For 100 and 2, this is 15,14,13,12,11,10,9,8,7,6
This works out to 1.5 times 10.

Identify this Algorithm: Slots and Pegs

I have a number of slots and pegs arranged in a straight line. The pegs can be moved and need to be moved to a slot each. A slot can be left empty only if all pegs are taken. When a peg is moved, it is not allowed to go past another peg. In other words the order of the pegs must be maintained. Preferably, the total distance moved by all pegs should be kept at a minimum. As far as possible, a peg should be placed in the nearest available slot.
All I want to know is: What field of mathematics deals with such a problem? What are the names of any well known algorithms which deal with similar problems? I am looking for Google fodder. Some keywords.
+--oooo-+--+---+---o--+------+--+-ooo+o-+-------o--+-----o-o-+-o
+ - Slots
o - Pegs
EDIT: I think that this visualization makes more sense. They are two separate tracks that need to line up.
Slots: +-------+--+---+------+------+--+----+--+----------+---------+--
Pegs: ---oooo------------o--------------ooo-o---------o--------o-o---o
EDIT: Just want to make it clear that the number of slots can be greater than, less than or equal to the number of pegs.
I think this is classic fodder for a dynamic programming solution. In fact, have a look a "sequence alignment" which might be another good search term on that wikipedia page.
The key insight is this:
Imagine you have your pegs as a list of peg positions (peg1:more pegs) and slots as a list of slot positions (slot1:more slots). Call this problem (peg1:pegs, slot1:slots). Then the solution is either peg1 in slot1 & the solution to (pegs, slots), or it is the solution to (peg1:pegs, slots).
This gives a recursive definition of how to solve it.
Or in pseudo-code (written in a functional programming style), imagine a function distance(peg, slot):
distance([]) = 0
distance((peg,slot):matches) = distance(peg,slot)+distance(matches)
solution(peg:[], slot:[]) = [(peg,slot)]
solution(peg:pegs, slot:slots) = if distance(a)<distance(b) then a else b
where a = solution(peg:pegs, slots) and b=(peg,slot):solution(pegs, slots)
This solution should be made more efficient by combining the distance into the data structure.
I don't know where this problem comes from but I am pretty sure that it's a form of combinatorial optimization, and more specifically one that can be solved using (integer) linear programming.
"the total distance moved by all pegs
should be kept at a minimum"
Unless I'm missing something, this is a non-problem.
Since the order of pegs must be maintained, you can just number the pegs 1, 2, 3, ...
+--1234-+--+---+---5--+------+--+-678+9-+-------10--+-----11-12-+-13
and the final state has to be peg 1 in slot 1, peg 2 in slot 2, etc.
+--1-+-2-+-3-+-4-+-5-+-6-+-7-+-8-+-9-+-10-+-11-+-12-+-13-+
Not being able to jump pegs past each other doesn't matter, each peg has to move a certain distance from it's starting point to its final point. As long as all moves are in the right direction and a peg never has to back up, then the distance each individual peg has to move is a simple constant (it doesn't depend on the order of the moves), and the sum of those distances, your cost function is constant, too.
I don't see any need for dynamic programming or linear programming optimization problem here.
If you introduce a cost for picking up a peg and setting it down, then maybe there's an optimization problem here, but even that might be trivial.
Edit in response to 1800 Information's comment
That is only true if the number of
slots is equal to the number of pegs -
this was not assumed in the problem
statement – 1800 INFORMATION (2 hours
ago)
OK, I missed that. Thanks for pointing out what I was missing. I'm still not convinced that this is rocket science, though.
Suppose # pegs > # holes. Compute the final state as above as if you had the extra holes; then pick the N pegs that got moved the furthest and remove them from the problem: those are the ones that don't get moved. Recompute ignoring those pegs.
Suppose # holes > # pegs. The correct final state might or might not have gaps. Compute the final state as above and look for where adjacent pegs got moved towards each other. Those are the points where you can break it into subproblems that can be solved trivially. There's one additional variable when you have holes on both ends of a contiguous subproblem -- where the final contiguous sequence begins.
Yes, it is a little more complicated than I thought at first, but it still seems like a little pencil-and-paper work should show that the solution is a couple of easily understood and coded loops.
Combinatorics. Combinatorial algorithms. Concrete mathematics. (Also the title of
an excellent and relevant book by Donald Knuth.
If the number of pegs == number of slots, there exists only one solution.
The first peg MUST go to the first slot, the next peg MUST go to the next slot, etc.
The the numbers are different, then it is slightly more complex because a peg or slot ( does not matter which one we can move ) can be moved to many places.
Brute force:
Suppose the number of objects are m pegs and n slots ( interchangeably ), m < n
For each way (n-m) slots can be
chosen ( refer to some combinatorics
algorithms to see how to do this )
There (n-m) chosen slots will be empty.
Fill the m remaining slots with pegs. Calculate distance moved. This become the same as the case discussed at the top.
Choose the arrangement with minimujm distance moved.
A recursive solution:
int solve(int pegs, int *peg_x, int slots, int *slot_x)
{
if (slots > pegs )
return solve(slots, slot_x, pegs, peg_x);
if (slots == 0 || pegs==0)
return 0; // Cannot move
int option1 = INT_MAX, options2 = INT_MAX;
if (pegs > slots ) // Can try skipping a peg
option1 = solve(pegs-1, peg_x+1 /* Move over one element */
slots, slot_x);
// pegs >= slots
option2 = solve(pegs-1, peg_x+1, slots-1, slot_x+1)
+ abs(peg_x[0]-slot_x[0]);
return min(option1, option2);
}
This solution still requires storing the results in a table so that no subproblem is solved multiple times, to be a dynamic solution.
Thinking .... will update .....
Queueing theory or mathematics...

Resources