Explanation behind codechef walk solution - explain

While solving the codechef problem WALK I figured out an algorithm to solve the problem using divide and conquer kind of approach , according to my algorithm we find the maximum in the array and divide our array into 2 parts (one from starting to the Max element and the other half from the next to Max element to the end of the array) and after that we find the initial velocity for first part(the part contesting the Max elemeny) of the array using : Max +(n-1) where n is the number of elements in that part of the array .... We do this thing for every part of the array and after computing the initial velocity for every part we check if the initial velocity of a part of array is less than or equal to the Max + 1 where Max is the maximum element of the part of the array just before the part under consideration , if this is the case we do nothing else we find out the difference between Max + 1 and initial velocity and add that difference to the initial velocity of the part previous to the part under consideration and we keep repeating this process until no more changes are required.
Now this algorithm will work surely but it will exceed the time limit .. When I saw the editorial it has one line solution of this problem .. Can someone please explain that solution to me I couldn't understand it .
Thanks in advance.

Let initial velocity be V.
When they are at the first(0-based indexing) shop, their velocity is still V, also, V >= W1.
When they cross it and go to the second shop, the velocity becomes V-1. and we know that V-1 >= W2.
Similarly When they cross it and go to the third shop, the velocity becomes V-2. and we know that V-2 >= W3.
Continuing this way, we see that this relation holds:
V-i >= Wi for all i in [0,n-1]
V0 >= W0 + 0
V1 >= W1 + 1
V2 >= W2 + 2
V3 >= W3 + 3 ...
Therefore, Vi >= Wi + i for all i.
Choose the V as which is maximum among all Wi+i

Related

Why is the meeting point in a loop same number of steps as the start of the linked list?

There is this apparently standard approach to find if a linked list has a cycle and then return the node that is at the start of the cycle which is floy's algorithm with slow/fast pointers.
The code and the logic is clear except 1 thing.
The approach is based on the assumption that the node in the loop that the pointers will meet is exactly the same number of steps as from the head of the list till the start of the loop.
That part is what I don't get.
So if Slow and Fast both start at the head of the list, when Slow does k steps and reaches the start of the loop, Fast will have done 2k steps and is effectively k steps into the loop.
So fast is ahead of slow by k steps and behind of slow (which is at the start of the loop) N - k where N is the loop size.
Since at each step fast approaches slow and fast is behind slow by N - k nodes, fast will reach slow in N - k steps.
At this point, slow would have done N - k steps and will be in node N - k.
Fast would have done 2(N - k) steps and will be at node 2N - 2k + k = 2N - k (since fast was at node k).
Since this is a loop 2N - k = N - k and hence they meet at node N - k.
But why is N - k node k steps from the start of the loop?
What am I misunderstanding here?
Here is what you are missing.
Whenever both pointers are in the loop and the fast pointer is a multiple of the loop length ahead, the fast pointer has lapped the slow an integer number of times and they are in the same place. If you continued they would separate and will lap again. And again. And again.
The whole reason why the algorithm works is this lapping behavior.
The first time that they meet, it might be at a strict multiple of the cycle length. For example if you have a chain of 24 nodes leading into a cycle of length 7 then they will first meet after 28 steps.
EDIT
I was explaining how the cycle detection worked, and not how the detection of the head worked. Here is an alternate explanation of that. In different words.
Suppose we have a chain of i nodes leading to a loop of length j. We initially run fast+slow pointers and they meet. In order to meet, the fast has to have gone some integer number of times more around the loop than the slow one did. So they meet after k*j steps.
At this point the slow pointer traveled k*j steps total, of which i steps were getting to the loop, so it has traveled k*j-i steps inside of the loop.
Now we put the fast pointer at the start, and advance them at the same rate. In another i steps the pointer at the start has reached the loop. The slow pointer, meanwhile, had previously traveled k*j-i steps inside of the loop, and now travelled another i steps for k*j steps inside of the loop. Since k*j is a multiple of the loop length, it is also back at the beginning and they meet again.
Let me give you another way to look at for this problem , and in the end, you might get your answer too.
Variables used for explanation:
N - total number of node links in linkedlist .
C - distance from head to the start point of loop
Y - distance from the starting of loop to the meeting point.
K - distance from the meeting point to the start of the loop.
So, we can drive some conclusions from these variables.
N = C + Y + K
Distance covered by slow pointer - Ds = C + Y
Distance covered by fast pointer - Df = N + Y
Here ,
N = 12
C = 2
Both Pointers will meet at node number 11, so Y = 8
K = 2
Since we know that fast pointer is 2 times faster than slow pointer, so Df = 2 * Ds
Using the relation between Df and Ds , and putting there values from above
N + Y = 2 * ( C + Y )
N + Y = 2*C + 2*Y
N = 2*C + Y
Using N's another relation ,
C + Y + K = 2*C + Y
K = C
This concludes that the distance between head and starting of loop equals to the distance between meeting point node and starting of the loop .
Try to understand this and always try to simplify the task by breaking it into smaller chunks .
Hope this will help.
Keep asking , keep growing :)

Generate list of real values, which sum up to fixed value and satisfy some constraints

I need to generate n random real values P[0], P[1], ..., P[n-1] which satisfy the following constraints:
Pmin[0] <= P[0] <= Pmax[0]
Pmin[1] <= P[1] <= Pmax[1]
...
Pmin[n-1] <= P[n-1] <= Pmax[n-1]
P[0] + P[1] + ... + P[n-1] = S
Any idea how to do this efficiently?
In general, it is not possible to solve this problem if choosing elements uniformly at random from the given ranges.
Example 1: Say that Pmin[i] = 0 and Pmax[i] = 1. Say that n = 10 and S = 100. Then there is no solution, since the greatest possible sum is 10.
Example 2: Say that Pmin[i] = 0 and Pmax[i] = 1. Say that n = 10 and S = 10. Then there is exactly one solution: choose P[i] = 1.
It is possible to write an algorithm such that the resulting sequence is chosen uniformly at random from the set of possible solutions; this is quite different from saying that the P[i] are uniformly distributed between Pmin[i] and Pmax[i].
The basic idea is to, at each stage, further restrict your range, as follows:
The beginning of the range ought to be the larger of the following two quantities: Pmin[i], or S - Smax[i] - P, where Smax[i] is the sum Pmax[i+1] + ... + Pmax[n] and P is the sum P[0] + ... + P[i]. This guarantees that you're picking a number large enough to eventually work.
The end of the range ought to be the smaller of the following two quantities:
Pmax[i], or S - Smin[i] - P, where Smin[i] is the sum Pmin[i+1] + ... + Pmin[n] and P is as before. This guarantees that you're picking a number small enough to eventually work.
If you are able to obey those rules when picking each P[i], there's a solution, and you will find one at random. Otherwise, there is not a solution.
Note that to actually make this select solutions at random, it's probably best to shuffle the indices, perform this algorithm, and then rearrange the sequence so that it's in the proper order. You can shuffle in O(n), do this algorithm (recommend dynamic programming here, since you can build solutions bottom-up) and then spit out the sequence by "unshuffling" the resulting sequence.
For every i, assign P[i] := Pmin[i]
Compute the sum
If sum>S, then stop (it's impossible)
For every i:
If P[i]+S-sum <= Pmax[i]
P[i] = P[i]+S-sum
Stop (it's done :-)
sum = sum+Pmax[i]-P[i]
P[i] = Pmax[i]
Go for next i
Stop (it's impossible)
Ooops, sorry, you said random... that's not so trivial. Let me think about it...
Run the previous algorithm to have a starting point. Now compute the total margin above and below. The margin above is the sum of individual margins Pmax[i]-P[i] for every i. The margin below is the sum of individual margins P[i]-Pmin[i] for every i.
Traverse all the elements but one in a random order, visiting each one of them exactly once. For every one of them:
Update the margin above and the margin below subtracting from them the contribution of the current element.
Establish a min and max for the current value taking into account that:
They must be in the interval [Pmin[i], Pmax[i]] AND
These min and max are near enough to P[i], so that changing other elements later can compensate changing P[i] to this min or max (that's what the margins above and below indicate)
Change P[i] to a random value in the calculated interval [min, max] and update the sum and the margins (I'm not 100% sure of how the margins should be updated here...)
Then adjust the remaining element to fit the sum S.
Regarding the traversal in random order, see the Knuth shuffles.

Can not understand knapsack solutions

In wikipedia the algorithm for Knapsack is as follows:
for i from 1 to n do
for j from 0 to W do
if j >= w[i] then
T[i, j] := max(T[i-1, j], T[i-1, j-w[i]] + v[i]) [18]
else
T[i, j] := T[i-1, j]
end if
end for
end for
And it is the same structures on all examples I found online.
What I can not understand is how does this code take into account the fact that perhaps the max value comes from a smaller knapsack? E.g. if the knapsack capacity is 8 then perhaps max value comes from capacity 7 (8 - 1).
I could not find anywhere logic to consider that perhaps the max value comes from a smaller knapsack. Is this wrong idea?
The Dynamic Programming solution of knapsack is basically recursive:
T(i,j) = max{ T(i-1,j) , T(i-1,j-w[i]) + v[i] }
// ^ ^
// ignore the element add the element, your value is increase
// by v[i] and the additional weight you can
// carry is decreased by w[i]
(The else condition is redundant in the recursive form if you set T(i,j) = -infinity for each j < 0).
The idea is exhaustive search, you start from one element and you have two possibilities: add it, or don't.
You check both options, and chose the best of those.
Since it is done recursively - you effectively checking ALL possibilities to assign the elements to the knapsack.
Note that the solution in wikipedia is basically a bottom-up solution for the same recursive formula
As I see, you have misunderstood the concept of knapsack. which I will describe here in details till we reach the code part.
First, there are two versions of the problem:
0-1 knapsack problem: here, the Items are indivisible, you either take an item or not. and can be solved with dynamic programming. //and this one is the one yo are facing problems with
Fractional knapsack problem: don't care about this one now.
For the first problem you can understand it as the following:
Given a knapsack with maximum capacity W, and a set S consisting of n items
Each item i has some weight wi and benefit value bi (all wi and W are integer values).
SO, How to pack the knapsack to achieve maximum total value of packed
items?
and in mathematical mouth:
and to solve this problem using Dynamic Programming We set up a table V[0..k, 0..W] with one row for each available item, and one column for each weight from 0 to W.
We need to carefully identify the sub-problems,
The sub-problem then will be to compute V[k,w], i.e., to find an optimal solution for
Sk= {items labeled 1, 2, .. k} in a knapsack of size w (maximum value achievable given capacity w and items 1,…, k)
So, we found this formula to solve our problem:
This algorithm only finds the max possible value that can be carried in the knapsack
i.e., the value in V[n,W]
To know the items that make this maximum value, this will be another topic.
I really hope that this answer will help you. I have an pp presentation that walks with you to fill the table and to show you the algorithm step by step. But I don't know how can I upload it to stackoverflow. let me know if any help needed.

Optimizing a DP on Intervals/Points

Well the problem is quite easy to solve naively in O(n3) time. The problem is something like:
There are N unique points on a number line. You want to cover every
single point on the number line with some set of intervals. You can
place an interval anywhere, and it costs B + MX to create an
interval, where B is the initial cost of creating an interval, and
X is half the length of the interval, and M is the cost per
length of interval. You want to find the minimum cost to cover every
single interval.
Sample data:
Points = {0, 7, 100}
B = 20
M = 5
So the optimal solution would be 57.50 because you can build an interval [0,7] at cost 20 + 3.5×5 and build an interval at [100,100] at cost 100 + 0×5, which adds up to 57.50.
I have an O(n3) solution, where the DP is minimum cost to cover points from [left, right]. So the answer would be in DP[1][N]. For every pair (i,j) I just iterate over k = {i...j-1} and compute DP[i][k] + DP[k + 1][j].
However, this solution is O(n3) (kind of like matrix multiplication I think) so it's too slow on N > 2000. Any way to optimize this?
Here's a quadratic solution:
Sort all the points by coordinate. Call the points p.
We'll keep an array A such that A[k] is the minimum cost to cover the first k points. Set A[0] to zero and all other elements to infinity.
For each k from 0 to n-1 and for each l from k+1 to n, set A[l] = min(A[l], A[k] + B + M*(p[l-1] - p[k])/2);
You should be able to convince yourself that, at the end, A[n] is the minimum cost to cover all n points. (We considered all possible minimal covering intervals and we did so from "left to right" in a certain sense.)
You can speed this up so that it runs in O(n log n) time; replace step 3 with the following:
Set A[1] = B. For each k from 2 to n, set A[k] = A[k-1] + min(M/2 * (p[k-1] - p[k-2]), B).
The idea here is that we either extend the previous interval to cover the next point or we end the previous interval at p[k-2] and begin a new one at p[k-1]. And the only thing we need to know to make that decision is the distance between the two points.
Notice also that, when computing A[k], I only needed the value of A[k-1]. In particular, you don't need to store the whole array A; only its most recent element.

Error in finding two subsets having equal sum

I have been trying to divide an array into two non empty disjoint subsets such that their sum are equal.
eg. A = {1,2,3,6,88,55,29}
one possible answer = 1+2+3 and 6
I have read mit tutorial on balanced partition problem but my constraints are different. I don't have to consider whole of set A(means its not necessary that A1 U A2 would result in A). Also another problem is limit of N. There are at most 100 distinct elements each (<= 100 ) .
I have also read THIS post related to my problem, but I couldn't get anything .
My present Algo --
p[1][a[0]] = 1
for i = 2 to n
for j = 0 to n*n
if( p[i][j] >= 2) stop
p[i][j] += j - a[i] > 0 ? ( p[i-1][j] + p[i-1][j-a[i]] ):0
p[i][j] += j == a[i] ? 1:0
p[i][j] += j < a[i] ? p[i-1][j]:0
explanation :
Search for sum j at position i. If we got count at position j >=2 means
there are more than two possibilities for summing up to j.
HERE is sample working code by me
I know this method cant take care of disjoint sets but I am unable to figure out any other approach.
I am in learning phase of Dynamic Prog. and I find it somewhat difficult. Can someone please help me in finding out the error in my current algorithm.
It seems your code don't go over all the subsets. The Power Set of a set of size n has 2^n-1 non empty elements, so I think this is the lower limit for the algorithmic complexity. You need to find an appropriate way to enumerate the subsets, as related by this other question on SO
In general subset generation is made by adding elements one by one. This allows you to compute the sum of an individual set in one addition if you use dynamic programming. Indeed, If you you have {1,2,3,6} and you save the value to 12, you just need to add 88 to find the sum of {1,2,3,6,88}.
You can find further optimization aside basic DP. For instance if you test
{88} > {1,2,3,6,29}
first then you don't need to test for any subset of {1,2,3,6,29} (the smaller sum) with {88}. At the same time you don't need to test any set containing 88 with {1,2,3,6,29}, as it will be always bigger... Now it requires to use recursion from bigger sets to smaller sets.

Resources