Algorithm for rope burning - algorithm

Generalized from a technical interview question:
Original question: There are two ropes, each rope takes 1 hour to
burn. But either rope has different densities at different points, so
there’s no guarantee of consistency in the time it takes different
sections within the rope to burn.
How do you use these two ropes to measure 45 minutes?
I have a generalized version:
There are n ropes, each rope takes x minutes to
burn (for simplicity assume x is positive integer). But the ropes have different densities at different points, so
there’s no guarantee of consistency in the time it takes different
sections within the ropes to burn.
Using these n ropes, what time quantity can you measure?
For example, with n = 1 and x = 60, I can measure 60 minute period
(burning one end of the rope), or 30 minute period (burning both ends
of the rope at the same time)
Of course my aim would be finding an algorithm with minimal complexity. I imagine the solution to this would involve dynamic programming, but I am not quite sure. My brute force solution is as followed:
Start at minute 0, we have n ropes, each takes x minutes to burn. For a given rope, we have choices either to burn both ends, one end, or not burning the rope at all. Let number of ropes that will not be burnt at this stage be x, number of ropes that will be burnt one end be y, and number of ropes that will not be burnt at all be z. We have x + y + z = n and that x,y,z are positive integers and z != 0. Consider all possible cases for x, y and z and add those cases to a stack/queue.
For each item in the stack/queue, determine how many minutes have passed when there is a rope finishes burning. Output the time that has passed (calculated based on how long the finished rope has burnt, and which ends were burnt at what time). Now we have another scenarios with certain amount of ropes that are being burnt. Repeat the step 1 argument with x + y + z = n - 1 (with constraints imposed on x, y, and z since some ropes are still burning and we cannot set the fire off) and add all the newly generated cases to the stack/queue.
Repeat 2. until n = 0 (All ropes finished burning)
Edit:
For n = 2 and x = 60, I've found that the following time period can be measured: 30, 60, 90, 120, 45 and 15.
As suggested, I posted the question on cs.stackexchange.com: https://cs.stackexchange.com/questions/32455/algorithm-for-rope-burning-problem

Well, here is my attempt to solve the problem with greater efficiency. I might have overlooked something, so be wary even if it seems to make sense.
We can start with a base state of 1 rope yields x minutes or x/2 minutes. Now, suppose it is possible to measure x_prev minutes with n ropes. Then, consider what happens if we add the n+1th rope. We can
Wait for the whole x_prev minutes to expire, then burn the next rope from 1 end. This means we can achieve x_prev + x minutes.
Wait for the whole x_prev minutes to expire, then burn the next rope from 2 ends. This means we can achieve x_prev + x/2 minutes.
Start burning the x_prev minutes as we burn the next rope from 1 end. This means we can achieve abs( x - x_prev ) minutes.
Start burning the x_prev minutes as we burn the next rope from 2 ends. This means we can achieve abs( x/2 - x_prev) minutes.
We do not care about a time t that was achieved with m with m<=n-1 ropes because we would have considered these four cases when we were adding the m+1-th rope.
These seem like the only four cases. So, in pseudocode, perhaps something like this
let solutions be a list of measurable times
def solve( n , x ):
if n <= 0
return, you cannot measure any times
else
#set up base case n=1
append x/2 and x to solutions
#we can be efficient by only checking the times achievable with n-1 ropes
#we will store the index of the first time that was recorded with n-1 ropes
#in start_idx
let start_idx be an index in the solutions array
#assume the array indices start at 0. then start_idx is the index
#of the first recorded time measurable with 1 rope.
start_idx = 0
#then continuously add additional ropes until we have n ropes
for i in 2..n
let solutions_to_add be a list
for j in start_idx..solutions.size() - 1
if solutions does not contain time+x
append time+x to solutions_to_add
if solutions does not contain time+x/2
append time+x/2 to solutions_to_add
if solutions does not contain abs( x-time )
append abs( x-time ) to solutions_to_add
if solutions does not contain abs( x/2-time )
append abs( x/2-time ) to solutions_to_add
#update the start_idx to be the starting index of times achievable with
#i ropes
start_idx = solutions.size()
#then add the achievable times with i ropes
for each time in solutions_to_add
append time to solutions
You can probably get O(1) run time for solution contains by using a boolean array for lookup. The overall algorithm seems to be O(n^2).
Is it correct? I'm not really sure if my four cases cover everything. I am pretty sure the induction-like process is correct.

Related

Finding minimum number of days

I got this question as a part of the interview and I am still unable to solve it.
It goes like this
A person has to complete N units of work; the nature of work is the same.
In order to get the hang of the work, he completes only one unit of work in the first day.
He wishes to celebrate the completion of work, so he decides to complete one unit of work in the last day.
Given that he is only allowed to complete x, x+1 or x-1 units of work in a day, where x is the units of work
completed on the previous day.
How many minimum days will he take to complete N units of work?
Sample Input:
6
-1
0
2
3
9
13
Here, line 1 represents the number of input test cases.
Sample Output:
0
0
2
3
5
7
Each number represents the minimum days required for each input in the sample input.
I tried doing it using the coin change approach but was not able to do so.
In 2k days, it's possible to do at most 2T(k) work (where T(k) is the k'th triangular number). In 2k+1 days, it's possible to do at most T(k+1)+T(k) at most work. That's because if there's an even (2k) number of days, the most work is 1+2+3+...+k + k+(k-1)+...3+2+1. Similarly, if there's an odd (2k+1) number of days, the most work is 1+2+3+...+k+(k+1)+k+...+3+2+1.
Given this pattern, it's possible to reduce the amount of work to any value (greater than 1) -- simply reduce the work done on the day with the most work, never picking the start or end day. This never invalidates the rule that the amount of work on one day is never more than 1 difference from an adjacent day.
Call this function F. That is:
F(2k) = 2T(k)
F(2k+1) = T(k)+T(k+1)
Recall that T(k) = k(k+1)/2, so the equations simplify:
F(2k) = k(k+1)
F(2k+1) = k(k+1)/2 + (k+1)(k+2)/2 = (k+1)^2
Armed with these observations, you can solve the original problem by finding the smallest number of days where it's possible to do at least N units of work. That is, the smallest d such that F(d) >= N.
You can, for example, use binary search to find d, or an optimal approach is to solve the equations. The minimal even solution has d/2 * (d/2 + 1) >= N which you can solve as a quadratic equation, and the minimal odd solution has (d+1)^2/4 >= N, which has a solution d = ceil(2sqrt(N)-1). Once you've found the minimal even and odd solutions, then you can pick the smaller of the two.
AS you want to have the minimum amounts of days you can just say yeah x+1, since if you want the minimum amount of days, BUT you have to consider that his last day x should be 1 so you have to break at a given point and go x-1, so now we have to determine the Breakpoint.
The Breakpoint is located in the middle of the days, since you start at 1 and want to end at 1.
For example you have to do 16 units so you distribute your days like:
Work done:
1234321.
7 days worked.
When you can't make an even Breakpoint like above repeat some values
5 = 1211
Samples:
2: 11
3: 111
9: 12321
13: 1234321
If you need to do exactly N units, not more, then you could use dynamic programming on the matrix a[x][y] where x is the amount of work done in the last day, y is the total amount of work, and a[x][y] is the the minimum number of days needed. You could use Dijkstra's algorithm to minimize a[1][N]. Begin with a[1][1]=1.

Matlab nearest neighbor / track points

I have a set of n complex numbers that move through the complex plane from time step 1 to nsampl . I want to plot those numbers and their trace over time (y-axis shows imaginary part, x-axis the real part). The numbers are stored in a n x nsampl vector. However in each time step the order of the n points is random. Thus in each time step I pick a point in the last time step, find its nearest neighbor in the current time step and put it at the same position as the current point. Then I repeat that for all other n-1 points and go on to the next time step. This way every point in the previous step is associated with exactly one point in the new step (1:1 relation). My current implementation and an example are given below. However my implementation is terribly slow (takes about 10s for 10 x 4000 complex numbers). As I want to increase both, the set size n and the time frames nsampl this is really important to me. Is there a smarter way to implement this to gain some performance?
Example with n=3 and nsampl=2:
%manually create a test vector X
X=zeros(3,2); % zeros(n,nsampl)
X(:,1)=[1+1i; 2+2i; 3+3i];
X(:,2)=[2.1+2i; 5+5i; 1.1+1.1i]; % <-- this is my vector with complex numbers
%vector sort algorithm
for k=2:nsampl
Xlast=[real(X(:,k-1)) imag(X(:,k-1))]; % create vector with x/y-coords from last time step
Xcur=[real(X(:,k)) imag(X(:,k))]; % create vector with x/y-coords from current time step
for i=1:size(X,1) % loop over all n points
idx = knnsearch(Xcur(i:end,:),Xlast(i,:)); %find nearest neighbor to Xlast(i,:), but only use the points not already associated, thus Xcur(i:end,:) points
idx = idx + i - 1;
Xcur([i idx],:) = Xcur([idx i],:); %sort nearest neighbor to the same position in the vector as it was in the last time step
end
X(:,k) = Xcur(:,1)+1i*Xcur(:,2); %revert x/y coordinates to a complex number
end
Result:
X(:,2)=[1.1+1.1i; 2.1+2i; 5+5i];
Can anyone help me to speed up this code?
The problem you are tying to solve is combinatorial optimizartion which is solved by the hungarian algorithm (aka munkres). Luckily there is a implementation for matlab available for download. Download the file and put it either on your search path or next to your function. The code to use it is:
for k=2:size(X,2)
%build up a cost matrix, here cost is the distance between two points.
pairwise_distances=abs(bsxfun(#minus,X(:,k-1),X(:,k).'));
%let the algorithm find the optimal pairing
permutation=munkres(pairwise_distances);
%apply it
X(:,k)=X(permutation,k);
end

Find minimum time required to collect C gifts from A machines given access to B bags?

I have an interview lined up for the next week and am practicing problems for the same. I came across this question, could you please help me with how to solve it?
There are A gift vending machines and you have B pouches to
collect the gifts in. Each gift vending machine has unlimited gifts.
Each machine starts dropping the gift at time Si second and keeps
dropping a gift every Ii seconds. You can arrange the pouches in
any way you like but once they are set below one machine, you cannot
move it to another machine. You need to collect a minimum of C gifts
in minimum time.
Input
The first line contains the integers A, B, C.
The second line contains integers, Si. ( separated with a space),
I goes from 1 to A.
The third line contains integers Ii ( separated with a space), I
goes from 1 to A.
Output
An integer which gives the minimum time calculated.
The method I thought was pretty inefficient. I thought that we can have all subsets with their cardinal number equal to B and then choose the one which gives the minimum time.
This approach seems to be brute force, so I'm looking for another alternative approach.
Can any of you please help me with it?
First of all write a function
int max_num_gifts(A,B,t,S[],l[])
which calculates the maximum number of gifts that you can collect with B bags in t time. This can be done in O(A) time: given S[] and l[] the number of gifts the machine A[i] drops is (t-S[i])/l[i]+1. Then get the top B machines which drop the most gifts. See How to find the kth largest element in an unsorted array of length n in O(n)? on how to do the selection in O(n) time.
Then you can just loop through the times t=1,2,... until max_num_gifts >= C. Or better still, you can use a binary search to find such a t: Start with t=1, then check t=2, t=4, t=8 etc until you get too big a number, then binary search for the required t.
The overall time complexity should be O(A* lg(T_min)).
One possible approach can be as follows:
Simulate each vending machine simultaneously by stepping through the events. For each machine calculate the time after which it will drop the gift and step through that time.
Also, maintain a priority queue of all the machines, ordered by the number of gifts dropped till present.
Then when the sum of gifts top B machines equals C, that is the minimum time T_min.
Order of complexity: O( T_min * A * logA )
First you have to sort the starting times S_i of the vending machines in A in ascending order. With this prerequisite, I think, the problem get's clearer if you write it as an equation:
Where \Theta is the Heaviside step function and the special braces denote the floor function.
A small python script to find T when gamma exceeds C could look like
import numpy as np
A=10
B=3
C=10
S=np.sort(np.random.randint(100, size=A))
gamma=0
t=1
while gamma<C:
for i in range(1, B):
gamma=(1 if t-S[i] > 0 else 0) * np.floor(t/2)
t = t+1
print "minimal t: %d" % t
I did not read the input values A, B and C from a file and generated the starting times S randomly between 0 and 100. You also would need to check if B<A.
For simplicity, let's make the following assumptions (we can relax these later and work out the edge cases):
Each machine produces a 'fractional gift' of 1/l[i] at every time step.
All S[i] are different, i.e., no two machines start dispensing at the same time.
Let's consider the two border cases first:
If we have more pouches than machines, we don't have to choose between them; at every time step S[i], we add a pouch to machine i, and keep collecting all gifts until we have a total of C.
If |B| = 1 (only one pouch), we add the pouch at the minimum S[i]. We keep stepping through time until either we reach C, or until another machine would have led to a higher total at that time, then switch the pouch due to 20-20 hindsight. Note that mathematically, the switch point is the intersection of the two lines that cross the x-axis at S[i], and have slope 1/l[i]. We will come back to that later.
Above considerations lead to the following general (naive) algorithm, in pseudocode.
def min_time_to_reach_c(S,l):
def function yield(m, t) = max(0, t-S[m])/l[m]
Active = {} # The currently best set of machines that we attach our pouches to
Inactive = {1,..,A} # The other machines
t = 0 # time step
sum = 0 # total gifts collected so far
gift_rate = 0 # gifts we receive at every time step
while sum < C:
if |Active| < B and t == S[m’] for some m’ in InActive:
# we have not used up all our pouches yet
Active += {m’}
InActive -= {m’}
gift_rate += l[m’]
else if yield(m’,t) > yield(m,t) for some m’ in InActive, m in Active: (*)
# for all successive time steps, m’ will be preferable to m
Active += {m’} - {m}
InActive -= {m’}
sum += yield(m’,t) - yield(m,t)
gift_rate += l[m’] - l[m]
sum += gift_rate
t += 1
return t
The complexity of this naive algorithm is at most O( t_min * A), if in each step (*) we determine the 'crossing' by finding the maximum (minimum) yields of the (In)Active sets by one linear pass each.
If A < t_min, we can actually do better by thinking about the geometry - it can be viewed as a sweep line algorithm. In fact, it is not necessary to visit each time point, we only need to look at the 'interesting' points where a machine starts or lines cross. In a preprocessing step, we calculate all time steps with intersections (if a line does not cross another one and is dominated, it can be dropped right away). At each such point, we can update our active set and the yield rate as above. We also calculate the distance to reach C at the current rate; if this occurs before the next S[i] or crossing, we are done.
The complexity of the sweep line algorithm is O(A^2) for the preprocessing step, plus another O(A^2) for the at most 2A update steps (or better, O(A log A) if we use a priority queue to keep track of the relative order of lines). Note that this is independent of t_min.
I think an interesting follow-up question would be: What would be the best strategy if you didn't know the S[i] and l[i] in advance?

Trying to gain intuition for work scheduling greedy algorithm

I have the following scenario: (since I don't know of a way to show LaTeX, here's a screenshot)
I'm having some trouble conceptualizing what's going on here. If I were to program this, I would probably attempt to structure this as some kind of heap where each node represents a worker, from earliest-to-latest, then run Prim's/Kruskal's algorithm on it. I don't know if I'm on the right track with that idea, but I need to flesh out my understanding of this problem so I can do the following:
Describe in detail the greedy choice
Show that if there's an optimal solution for which the greedy choice was not made, then an exchange can be made to conform with the greedy choice
Know how to implement a greedy algorithm solution, and its running time
So where should I be going with this idea?
This problem is very similar in nature to "Roster Scheduling problems." Think of the committee as say a set of 'supervisors' and you want to have a supervisor present, whenever a worker is present. In this case, the supervisor comes from the same set as the workers.
Here are some modeling ideas, and an Integer Programming formulation.
Time Slicing Idea
This sounds like a bad idea initially, but works really well in practice. We are going to create a lot of "time instants" T i from the start time of the first shift, to the end time of the very last shift. It sometimes helps to think of
T1, T2, T3....TN as being time instants (say) five minutes apart. For every Ti at least one worker is working on a shift. Therefore, that time instant has be be covered (Coverage means there has to be at least one member of the committee also working at time Ti.)
We really need to only worry about 2n Time instants: The start and finish times of each of the n workers.
Coverage Property Requirement
For every time instant Ti, we want a worker from the Committee present.
Let w1, w2...wn be the workers, sorted by their start times s_i. (Worker w1 starts the earliest shift, and worker wn starts the very last shift.)
Introduce a new Indicator variable (boolean):
Y_i = 1 if worker i is part of the committeee
Y_i = 0 otherwise.
Visualization
Now think of a 0-1 matrix, where the rows are the SORTED workers, and the columns are the time instants...
Construct a Time-Worker Matrix (0/1)
t1 t2 t3 t4 t5 t6 ... tN
-------------------------------------------
w1 1 1
w2 1 1
w3 1 1 1
w4 1 1 1
...
...
wn 1 1 1 1
-------------------------------------------
Total 2 4 3 ... ... 1 2 4 5
So the problem is to make sure that for each column, at least 1 worker is Selected to be part of the committee. The Total shows the number of candidates for the committee at each Time instant.
An Integer Programming based formulation
Objective: Minimize Sum(Y_i)
Subject to:
Y1 + Y2 >= 1 # coverage for time t1
Y1 + Y2 + Y3 >= 1 # coverage for time t2
...
More generally, the constraints are:
# Set Covering constraint for time T_i
Sum over all worker i's that are working at time t_i (Y_i) >= 1
Y_i Binary for all i's
Preprocessing
This Integer program, if attempted without preprocessing can be very difficult, and end up choking the solvers. But in practice there are quite a number of preprocessing ideas that can help immensely.
Make any forced assignments. (If ever there is a time instant with only one
worker working, that worker has to be in the committee ∈ C)
Separate into nice subproblems. Look at the time-worker Matrix. If there are nice 'rectangles' in it that can be cut out without
impacting any other time instant, then that is a wholly separate
sub-problem to solve. Makes the solver go much, much faster.
Identical shifts - If lots of workers have the exact same start and end times, then you can simply choose ANY one of them (say, the
lexicographically first worker, WLOG) and remove all the other workers from
consideration. (Makes a ton of difference in real life situations.)
Dominating shifts: If one worker starts before and stays later than any other worker, the 'dominating' worker can stay, all the
'dominated' workers can be removed from consideration for C.
All the identical rows (and columns) in the time-worker Matrix can be fused. You need to only keep one of them. (De-duping)
You could throw this into an IP solver (CPLEX, Excel, lp_solve etc.) and you will get a solution, if the problem size is not an issue.
Hope some of these ideas help.

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.

Resources