egg_drop
% egg_drop.pi (in Picat)
% by N.F. Zhou, Jan. 24, 2016
% https://code.google.com/codejam/contest/32003/dashboard#s=p2
% Practice Problems
% Problem C. Egg Drop
%
% to use: picat egg_drop < input_file > output_file
%
main =>
T = read_int(),
foreach (TC in 1..T)
F = read_int(), D = read_int(), B = read_int(),
do_case(TC, F, D, B)
end.
do_case(TC, F, D, B) =>
MF = max_f(D, B),
min_d(F, MD, B),
min_b(F, D, MB),
printf("Case #%w: %w %w %w\n", TC, MF, MD, MB).
% maximize F for given D and B
max_f(D, B) = F, D >= 100000, B >= 2 => F = -1.
max_f(D, B) = F, D >= 10000, B >= 3 => F = -1.
max_f(D, B) = F, D >= 1000, B >= 4 => F = -1.
max_f(D, B) = F, B > D => F = max_f(D, D).
max_f(D, B) = f(D, B).
table
f(_, 0) = 0.
f(D, 1) = D.
f(0, _) = 0.
f(1, _) = 1.
f(D, B) = F =>
F1 = f(D-1,B),
F2 = f(D-1,B-1),
if F1 == -1 ; F2 == -1 then
F = -1
else
F0 = F1+F2+1,
F = cond(F0 >= 2**32, -1, F0)
end.
% minimize D for given F and B
min_d(F, D, B) =>
bsearch_d(0, F, F, D, B).
bsearch_d(From, To, F, D, B), From >= To =>
D = cond((max_f(From, B) >= F ; max_f(From, B) == -1), From, From+1).
bsearch_d(From, To, F, D, B) =>
Mid = (From+To) div 2,
if max_f(Mid, B) == F then
D = Mid
elseif max_f(Mid, B) == -1 ; max_f(Mid, B) > F then
bsearch_d(From, Mid-1, F, D, B)
else
bsearch_d(Mid+1, To, F, D, B)
end.
% minimize B for given F and D
min_b(F, D, B) =>
bsearch_b(0, F, F, D, B).
bsearch_b(From, To, F, D, B), From >= To =>
B = cond((max_f(D, From) >= F ; max_f(D, From) == -1), From, From+1).
bsearch_b(From, To, F, D, B) =>
Mid = (From+To) div 2,
if max_f(D, Mid) == F then
B = Mid
elseif max_f(D, Mid) == -1 ; max_f(D, Mid) > F then
bsearch_b(From, Mid-1, F, D, B)
else
bsearch_b(Mid+1, To, F, D, B)
end.