Google Code Jam 2014 Qualifiers

Google Code Jam has always been a competition I have cherished, simply because the problems they post are brilliant and the closest to reality as compared to problems of other competitions. They’re always fun to read, disect & solve, more often than not, the solutions are reasonably trivial (1)Especially for the qualifiers yet extremely subtle & deceptive.

Today I want to share the solutions of 3 problems I was able to solve, the code should pretty much speak for itself because none of it is very complex.

Magic Trick #

This one was the easiest of all, more of a warmup I suppose. Here’s the solution :

def get_ans
    gets.to_i
end

def get_arr
    arr = []
    4.times do
        arr << gets.split.map(&:to_i)
    end
    arr
end

def get_ans_arr
    [get_ans, get_arr]
end

def pout(x, y)
    puts "Case ##{x}: #{y}"
end

def solve(a1, arr1, a2, arr2)
    int = arr1[a1-1] & arr2[a2-1]
    case int.size
    when 0
        'Volunteer cheated!'
    when 1
        int[0]
    when 2..4
        'Bad magician!'
    end
end

gets.to_i.times do |i|
    a1, arr1 = get_ans_arr
    a2, arr2 = get_ans_arr
    pout(i+1, solve(a1, arr1, a2, arr2))
end

Based on Cookie Clicker game developed by Orteil, this one was slightly trickier, and required a little bit of math. I solved it with a recursive algorithm first, then optimized it into an iterative one to pass for the large input. Here’s my solution with both recursive and iterative parts :

RATE = 2.0

def trunc(y)
    return y.round(7)
end

def pout(x, y)
    puts "Case ##{x}: #{trunc(y)}"
end

def solve_rec(c, f, x, r, t)
    return t + (x/r) if x <= c || (t + c/r + x/(r+f)) >= (t + x/r)

    t += c/r
    r += f
    solve_rec(c, f, x, r, t)
end

def solve_itr(c, f, x)
    t, r = 0.0, RATE
    return x/r if x <= c

    while (t + c/r + x/(r+f)) &lt; (t + x/r)
        t += c/r
        r += f
    end
    t + x/r
end

gets.to_i.times do |i|
c, f, x= gets.split.map(&:to_f)

# pout(i+1, solve_rec(c, f, x, RATE, 0.0))

pout(i+1, solve_itr(c, f, x))
end

Deceitful War #

This one was really subtle, easy enough to understand but hard to implement. It took me a while to put my understanding of how much being deceitful at the game called War translated to my points. Here too I solved both the normal game War and Deceitful War recursively first (2)It’s just easier to think recursively thanks to Lisp , then translated those to their iterative counterparts. Here is my solution with both recursive & iterative parts :

def pout(i, x, y)
    puts "Case ##{i}: #{x} #{y}"
end

def pick_kn(kb, nbs)
    kb.find do |kbi|
        kbi > nbs
    end || kb.first
end

def solve_war_rec(nb, kb, s)
    return nb[0] > kb[0] ? s + 1 : s if nb.size == 1 && kb.size == 1

    nbs = nb.shift
    kbs = kb.delete(pick_kn(kb, nbs))
    s += nbs > kbs ? 1 : 0
    solve_war_rec(nb, kb, s)
end

def solve_war_itr(nb, kb)
    return nb[0] > kb[0] ? 1 : 0 if nb.size == 1 && kb.size == 1

    s = 0
    while nb.size > 0 && kb.size > 0
        nbs = nb.pop
        kbs = kb.delete(pick_kn(kb, nbs))
        s += nbs > kbs ? 1 : 0
    end
    s
end

def pick_dkn(kb, nbs)
    kb.select do |kbi|
        kbi < nbs
    end.last || kb.first
end

def solve_dwar_rec(nb, kb, s)
    return nb[0] > kb[0] ? s + 1 : s if nb.size == 1 && kb.size == 1

    nbs = nb.pop
    kbs = kb.delete(pick_dkn(kb, nbs))
    s += nbs > kbs ? 1 : 0
    solve_dwar_rec(nb, kb, s)
end

def solve_dwar_itr(nb, kb)
    return nb[0] > kb[0] ? 1 : 0 if nb.size == 1 && kb.size == 1

    s = 0
    while nb.size > 0 && kb.size > 0
        nbs = nb.pop
        kbs = kb.delete(pick_dkn(kb, nbs))
        s += nbs > kbs ? 1 : 0
    end
    s
end

gets.to_i.times do |i|
    gets.to_i
    nb = gets.split.map(&:to_f).sort
    kb = gets.split.map(&:to_f).sort
    # pout(i+1, solve_dwar_rec(nb.clone, kb.clone), solve_war_rec(nb.clone, kb.clone))
    pout(i+1, solve_dwar_itr(nb.clone, kb.clone), solve_war_itr(nb.clone, kb.clone))
end
comments powered by Disqus