• "Feed Pigeons" Review

Pigeons

Hi, CiO Friends!

On our landing page you can find one mission text with solutions. And this is "Feed Pigeons". I'm not sure why but this mission can trouble new players.

Description

I start to feed one of the pigeons. A minute later two more fly by and a minute after that another 3. Then 4, and so on (Ex: 1+2+3+4+...). One portion of food lasts a pigeon for a minute, but in case there's not enough food for all the birds, the pigeons who arrived first ate first. Pigeons are hungry animals and eat without knowing when to stop. If I have N portions of bird feed, how many pigeons will be fed with at least one portion of wheat?

Simple

The simplest way to solve it is using step-by-step model and repeat all stages of feeding. Create minute counter and for each minute increasing we reduce wheat portions and add new pigeons. But we should be careful for the step when we have portions less than pigeons, because for this case we feed "old" pigeons first, even if they are fed already. In our solution "minute" is the same as a quantity of new arrived pigeons.

def checkio(portions):
    """Simple and straight"""
    fed = minute = pigeons = 0
    while portions >= 0:
        portions -= pigeons
        minute += 1
        if portions <= 0:
            return fed
        if minute < portions:
            fed += minute
            portions -= minute
        else:
            fed += portions
            return fed
        pigeons += minute
    return fed

Sequence

But if we will write solution results for several input values, then we can notice that these numbers create a sequence.

1, 1, 2, 3, 3, 3, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10...

I hope you see a pattern. Now we need to write a generator for this and honestly we can receive all answer for 1 to N in one run.

def checkio(portions):
    step, i, results = 1, 1, []
    while len(results) < portions + 1:
        results.extend([i] * (i + 1))
        results.extend(range(i + 1, i + 1 + step))
        step += 1
        i += step
    return results[portions]

Math

But this mission can be solved with pure mathematics (ok, almost pure) and O(1) complexity. And @bunnychai proved this with "Arithmetic" solution

def checkio(number):
    k = int((6 * number) ** (1.0 / 3))
    if k * (k + 1) * (k + 2) > 6 * number:
        k -= 1
    t = k * (k + 1) / 2
    s = t * (k + 2) / 3
    return t + max(number - s - t, 0)

and an another variant by @DiEvAl in "First" solution. Here you can find an explanation of the math.

def checkio(n):
    # After m minutes there are m(m+1)/2 birds and we've used m(m+1)(m+2)/6 portions of wheet.
    # Solving the equation x(x+1)(x+2)=6n (http://www.wolframalpha.com/input/?i=x%28x%2B1%29%28x%2B2%29%3D6n)
    # gives us only 1 positive real root for a > 0:
    # x = (sqrt(3) sqrt(243 a^2-1)+27 a)^(1/3)/3^(2/3)+1/(3^(1/3) (sqrt(3) sqrt(243 a^2-1)+27 a)^(1/3))-1
    t = ((9*n**2 - 1/27) ** (1/2) + 3*n) ** (1/3)
    x = t + 1/(3*t) - 1
    m = int(x)
    return max(m*(m+1)/2, n - m*(m+1)*(m+2)/6)

Creative

And as usually "Creative" solutions as dessert. For example this golf solution by @melpon

f=lambda n,y=0,i=0:n<y and max(n,y-i+1)or f(n-y,sum(range(i+1)),i+1)
checkio=f

And @veky with his "Optimal" solution, where math twisted with binary search. You can find hints how it's work in comments or ask the author of this solution.

def pbs(cond, start=0):
    """last int after start satisfying cond
    Precondition: cond(n)=>cond(n-1) & cond(start) & exists n>start not cond(n)
    Complexity: max. 2*ld(result-start), calls cond on distinct numbers only"""
    step = 1
    while cond(start + step): step <<= 1
    start += step >> 1
    step >>= 2
    while step:
        if cond(start + step): start += step
        step >>= 1
    return start
​
def checkio(n):
    k = pbs(lambda k: k**3 - k <= 6*n)
    return max(n - (k**3 - k)//6, (k**2 - k)//2)

That's all folks. Be careful with Hungry Pigeons ;-)

Valentin Bryukhanov aka Bryukh

Welcome to CheckiO - games for coders where you can improve your codings skills.

The main idea behind these games is to give you the opportunity to learn by exchanging experience with the rest of the community. Every day we are trying to find interesting solutions for you to help you become a better coder.

Join the Game