fun root(n) =
if n>0 then
let
val x = root(n div 4);
in
if (2*x+1)*(2*x+1) > n then 2*x
else 2*x+1
end
else 0;
fun isPrime(n,c) =
if c<=root(n) then
if n mod c = 0 then false
else isPrime(n,c+1)
else true;
The time complexity for the root(n) function here is O(log(n)): the number is getting divided by 4 at every step and the code in the function itself is O(1). The time complexity for the isPrime function is o(sqrt(n)) as it runs iteratively from 1 to sqrt(n). The issue I face now is what would be the order of both functions together? Would it just be O(sqrt(n)) or would it be O(sqrt(n)*log(n)) or something else altogether?
I'm new to big O notation in general, I have gone through multiple websites and youtube videos trying to understand the concept but I can't seem to calculate it with any confidence... If you guys could point me towards a few resources to help me practice calculating, it would be a great help.
root(n) is O(log₄(n)), yes.
isPrime(n,c) is O((√n - c) · log₄(n)):
You recompute root(n) in every step even though it never changes, causing the "... · log₄(n)".
You iterate c from some value up to root(n); while it is upwards bounded by root(n), it is not downards bounded: c could start at 0, or at an arbitrarily large negative number, or at a positive number less than or equal to √n, or at a number greater than √n. If you assume that c starts at 0, then isPrime(n,c) is O(√n · log₄(n)).
You probably want to prove this using either induction or by reference to the Master Theorem. You may want to simplify isPrime so that it does not take c as an argument in its outer signature, and so that it does not recompute root(n) unnecessarily on every iteration.
For example:
fun isPrime n =
let
val sq = root n
fun check c = c > sq orelse (n mod c <> 0 andalso check (c + 1))
in
check 2
end
This isPrime(n) is O(√n + log₄(n)), or just O(√n) if we omit lower-order terms.
First it computes root n once at O(log₄(n)).
Then it loops from 0 up to root n once at O(√n).
Note that neither of us have proven anything formally at this point.
(Edit: Changed check (n, 0) to check (n, 2), since duh.)
(Edit: Removed n as argument from check since it never varies.)
(Edit: As you point out, Aryan, looping from 2 to root n is indeed O(√n) even though computing root n takes only O(log₄(n))!)
I'm curious about the GCD problem. I am taking the Coursera Algorithmic toolbox course, and it states that the naive solution to the problem is:
for d from 1 to a+b:
if d|a and d|b:
best(or max) d
return best
I'm confused by this though. Wouldn't the maximum possible divisor be min(a,b) instead of a+b? since the smaller of the two couldn't possibly be divided by the larger of the two?
Yes, you are right. You could rewrite the algorithm, that the loop stop by min(a,b)
for d from 1 to min(a,b):
if d|a and d|b:
best(or max) d
return best
This implementation is faster than the first one. You could still improve it by looping backward:
for d from min(a,b) to 1:
if d|a and d|b:
break
return d
The following algorithm is necessary in a code generation problem that I am tackling. My current algorithm is O(n^2) but I feel like there is a better way to do it.
Suppose I have a predicate function for computing whether x < y.
less?: (x:T, y:T) -> True|False
I know a-priori that this relation is transitive. Such that,
less?(a, b) and less?(b, c)
implies
less?(a, c)
I would like to compute the dependency graph for a set of objects (x1, ..., xn). It should look like:
x1 => (x2, x4, x5)
x2 => (x3)
x5 => (x7)
x10 => ()
etc...
where each node, xi, is associated with a list of xj such that less?(xj, xi) is true. The easiest way to compute this graph is to call less? on all possible pairs of (xi, xj). But the less? relation is expensive and I would like to minimize the calls to less?
Thanks for your help.
-Patrick
If the < relation is sufficiently expensive you might gain by maintaining a matrix in which to store the current state of knowledge about a vs b. We can have a < b, !(a < b), or unknown. Then when you compute a comparison of a vs b, store that in the matrix and look for deductions about a vs c and b vs c for every possible c for which the result is as yet unknown. Do you also have a < b => !(b < a)?
With e.g. a vs b and b vs c there are only a finite number of possibilities to check for compatibility and incompatibility to see where deductions are possible but clearly a < b and b < c => a < c. Because of this we also have a < b and !(a < c) => !(b < c). Perhaps if you write out all possibilities you can find more.
I would be inclined to slowly grow a square of known values, adding new variables one by one chosen in a random order, so at stage i you know the entire contents of the matrix for the first i randomly chosen variables. As you add each new variable I would compare it with the variables already worked on in a random order. You are making every deduction possible. If there is a very clever variable comparison order you might hope that with a random comparison order it will be close enough to the optimal order that you won't be much more inefficient than it.
I have my doubts about this in the worst case. If you never find a < b for any a, b, I think you have to check every possibility.
Hot or cold.
I think you have to do some sort of binary search but I'm not sure how.
Your goal is the guess a secret integer between 1 and N. You
repeatedly guess integers between 1 and N. After each guess you learn
if it equals the secret integer (and the game stops); otherwise
(starting with the second guess), you learn if the guess is hotter
(closer to) or colder (farther from) the secret number than your
previous guess. Design an algorithm that finds the secret number in lg
N + O(1) guesses.
Hint: Design an algorithm that solves the problem in lg N + O(1)
guesses assuming you are permitted to guess integers in the range -N
to 2N.
I've been racking my brain and I can't seem to come up with a a lg N + O(1).
I found this: http://www.ocf.berkeley.edu/~wwu/cgi-bin/yabb/YaBB.cgi?board=riddles_cs;action=display;num=1316188034 but could not understand the diagram and it did not describe other possible cases.
Suppose you know that your secret integer is in [a,b], and that your last guess is c.
You want to divide your interval by two, and to know whether your secret integer lies in between [a,m] or [m,b], with m=(a+b)/2.
The trick is to guess d, such that (c+d)/2 = (a+b)/2.
Without loss of generality, we can suppose that d is bigger than c. Then, if d is hotter than c, your secret integer will be bigger than (c+d)/2 = (a+b)/2 = m, and so your secret integer will lie in [m,b]. If d is cooler than c, your secret integer will belong to [a,m].
You need to be able to guess between -N and 2N because you can't guarantee that c and d as defined above will always be [a,b]. Your two first guess can be 1 and N.
So, your are dividing your interval be two at each guess, so the complexity is log(N) + O(1).
A short example to illustrate this (results chosen randomly):
Guess Result Interval of the secret number
1 *** [1 , N ] // d = a + b - c
N cooler [1 , N/2 ] // N = 1 + N - 1
-N/2 cooler [N/4 , N/2 ] //-N/2 = 1 + N/2 - N
5N/4 hotter [3N/8, N/2 ] // 5N/4 = N/4 + N/2 + N/2
-3N/8 hotter [3N/8, 7N/16] //-3N/8 = 3N/8 + N/2 - 5N/4
. . . .
. . . .
. . . .
Edit, suggested by #tmyklebu:
We still need to prove that our guess will always fall in bewteen [-N,2N]
By recurrence, suppose that c (our previous guess) is in [a-(a+b), b+(a+b)] = [-b,a+2b]
Then d = a+b-c <= a+b-(-b) <= a+2b and d = a+b-c >= a+b-(a+2b) >= -b
Initial case: a=1, b=N, c=1, c is indeed in [-b,a+2*b]
QED
This was a task at IOI 2010, for which I sat on the Host Scientific Committee. (We asked for an optimal solution instead of simply lg N + O(1), and what follows is not quite optimal.)
Not swinging outside -N .. 2N and using lg N + 2 guesses is straightforward; all you need to do is show that the obvious translation of binary search works.
Once you have something that doesn't swing outside -N .. 2N and takes lg N + 2 guesses, do this:
Guess N/2, then N/2+1. This tells you which half of the array the answer is in. Then guess the end of that half-array. You're either in one of the two "middle" quarters or you're in one of the two "end" quarters. If you're in a middle quarter, do the thing before and you win in lg N + 4 guesses. The ends are slightly trickier.
Suppose I need to guess a number in 1 .. K without straying outside 1 .. N and my last guess was 1. If I guess K/2 and I'm colder, then I next guess 1; I spent two guesses to get a similar subproblem that's 1/4 the size. If K/2 is hotter, I know the answer is in K/4 .. K. Guess K/2-1 next. The two subcases are K/4 .. K/2-1 and K/2 .. K, both of which are nice. But it took me three guesses to (in the worst-case) halve the size of the problem; if I ever do this, I wind up doing lg N + 6 guesses.
The solution is close to binary search. At each step you have an interval that the number can be in. Start with the whole interval [1, N]. First guess both ends - that is the numbers 1 and N. One of them will be closer, thus you will know that now the number you are searching for is in [1, N/2] or in [N/2 + 1, N](considering N even for simplicity). Now you go to the next step having a twice smaller interval. Continue using the same approach. Keep in mind that you've already probed one of the ends, however it may not be your last guess.
I am not sure what you mean by lg N + O(1), but the approach I suggest will perform O(log(N)) operations and in the worst case it will do exactly log4(N) probes.
Here're my two cents for this problem, since I got obsessed with it for two days. I'm not going to say anything new to what others have already said, but I'm going to explain it in a way that might get some people to understand the solution easily(or at least that was the way I managed to understand it).
Drawing from the ~ 2 lg N solution, if I knew that solution existed in [a, b] I'd want to know if it's in the left half [a, (a + b) / 2] or the right half [(a + b) / 2, b], with the point (a + b) / 2 separating the two halves. So what do I do? I guess a then b; if I get colder with b I know I'm in the first(left) half, if I get hotter I know I'm in the second(right) one. So guessing a and b is the way to know the secret integer position with respect to the mid point (a + b) / 2. However a and b aren't the only points that I can guess at to know the secret position. (a - 1, b + 1), (a - 2, b + 2), ... etc are all valid pairs of points to guess at to know the secret position, as the mid point of all these pairs is (a + b) / 2, the mid point of the original interval [a, b]. In fact any two numbers c and d such that (c + d) / 2 = (a + b) / 2 can be used.
So considering [a, b] as the interval we know the secret integer exists within, take c to be the last number we guessed. We want to determine the position of the secret with respect to the mid point (a + b) / 2, so we a new number d to guess at to know the secret relative position to (a + b) / 2. How do we know such number d? By solving the equation (c + d) / 2 = (a + b) / 2, which yields d = a + b - c. Guessing at that d, we shrink the range [a, b] appropriately based on the answer(colder or hotter) and then repeat the process taking d as our last guess and trying a new guess at number e for example with the same conditions.
To establish the initial conditions, we should start with a = 1, b = N, and c = 1. We guess at c to establish a reference(since the first guess can't tell you anything useful as there were no prior guesses). We then proceed with new guesses and adjusting the enclosing interval as appropriate with each guess. The table in #R2B2's answer explains it all.
You have to be vigilant however when trying to code this solution. When I tried to code it in python, I first ran into the mistake of getting [a, b] stuck when it was small enough(like [a, a + 1]) where neither a nor b would move inwards. I had to phase the cases where the interval size was 2 outside the loop and handle them separately(like I did with intervals with size 1 also).
the task is quite brain cracking
but I'll try to keep it simple
to solve the problem in 2lnN let's make following guesses:
1 and N : to decide which half is hotter (1, N/2) or (N/2, N), for example (N/2, N) is the hotter half, then let's make next guesses
N/2 and N : again to decide which half is hotter (N/2, 3/4N) or (3/4N, N) and so on
... so we need 2 guesses for every half-division, therefore we should make 2 * lnN guesses.
here we see that each time we need to repeat one of previous intervals' borders one more time - in our example point 'N' is repeated.
to solve the problem in 1*lnN guesses instead of 2*lnN, we need to find way to spend only one guess for each intervals' half-division, good illustration of such method is depicted on image at http://www.ocf.berkeley.edu/~wwu/cgi-bin/yabb/YaBB.cgi?board=riddles_cs;action=display;num=1316188034
the idea is to avoid repeating one of border points of each interval again in subsequent steps, but be smart to spend one guess for each half-division step by mirroring points.
the smart idea is that when we want to decide which half of current interval is hotter, we don't need to try only its borders, but we can as well try any points located outside its borders, these guessing points must be at equal distances (in other words mirrored) relatively to the center of interesting interval, nothing bad even if these guessing points are negative (i.e. < 0) or if they are > N (this is not prohibited by the conditions of the task)
so to guess the secret we can freely make guesses using pounts in interval (-N, 2N)
public class HotOrCold {
static int num=5000;// number to search
private static int prev=0;
public static void main(String[] args) {
System.out.println(guess(1,Integer.MAX_VALUE));
}
public static int guess(int lo,int hi) {
while(hi>=lo) {
boolean one=false;
boolean two=false;
if(hi==lo) {
return lo;
}
if(isHot(lo)) {
one=true;
}
if(isHot(hi)) {
two=true;
}
if(!(one||two)) {
return (hi+lo)/2;// equal distance
}
if(two) {
lo=hi-(hi-lo)/2;
continue;//checking two before as it's hotter than lo so ignoring the lo
}
if(one) {
hi=lo+(hi-lo)/2;
}
}
return 0;
}
public static boolean isHot(int curr) {
boolean hot=false;
if(Math.abs(num-curr)<Math.abs(num-prev)) {
hot=true;
}
prev=curr;
return hot;
}
}
Currently I have this linear programming model:
Max X
such that:
Max_a(Min_b(F(a,b,X))) <= some constant
*Max_a meaning to maximize the following equation by just changing a, and the same applies to Min_b
Now, the problem becomes how to linearize the constraint part. Most of the current Minmax linearization papers talks about Minmax as an objective. But how to linearize it if it was an constraint??
Thanks
Preliminary remark: the problem you describe is not a "linear programming model", and there is no way to transform it into a linear model directly (which doesn't mean it can't be solved).
First, note that the Max in the constraint is not necessary, i.e. your problem can be reformulated as:
Max X
subject to: Min_b F(a, b, X) <= K forall a
Now, since you are speaking of 'linear model', I assume that at least F is linear, i.e.:
F(a, b, X) = Fa.a + Fb.b + FX.X
And the constraint can obviously be written:
Fa.a + Min_b Fb.b + FX.X <= k forall a
The interesting point is that the minimum on b does not depend on the value of a and X. Hence, it can be solved beforehand: first find u = Min_b Fb.b, and then solve
Max X
subject to Fa.a + FX.X <= k - u forall a
This assume, of course, that the domain of a and b are independant (of the form AxB): if there are other constraints coupling a and b, it is a different problem (in that case please write the complete problem in the question).