48 lines
1.5 KiB
Python
48 lines
1.5 KiB
Python
|
from fractions import Fraction
|
||
|
|
||
|
|
||
|
def euler_100():
|
||
|
F_ONE_HALF = Fraction(1, 2)
|
||
|
prev_blue_discs, blue_discs = 10, 10
|
||
|
while True:
|
||
|
# Brute force search blue discs
|
||
|
blue_discs += 1
|
||
|
|
||
|
# Binary search red discs
|
||
|
red_upper = blue_discs // 2
|
||
|
red_lower = 1
|
||
|
while red_upper != red_lower:
|
||
|
red_discs = red_lower + (red_upper - red_lower) // 2
|
||
|
total_discs = blue_discs + red_discs
|
||
|
f1 = Fraction(blue_discs, total_discs)
|
||
|
f2 = Fraction(blue_discs - 1, total_discs - 1)
|
||
|
f = f1 * f2
|
||
|
if f == F_ONE_HALF:
|
||
|
# End criterion by Euler Problem
|
||
|
if total_discs > 10**12:
|
||
|
return blue_discs
|
||
|
|
||
|
# The ration between two solutions seems to be constant so we
|
||
|
# can get the next larger candidate for blue_discs much
|
||
|
# quicker.
|
||
|
ratio = blue_discs / prev_blue_discs
|
||
|
# print("blue_discs={} ratio={}".format(blue_discs, ratio))
|
||
|
prev_blue_discs = blue_discs
|
||
|
blue_discs = int(blue_discs * ratio)
|
||
|
break
|
||
|
elif f < F_ONE_HALF:
|
||
|
red_upper = red_discs
|
||
|
else:
|
||
|
red_lower = red_discs
|
||
|
|
||
|
# No solution for current number of blue discs
|
||
|
if abs(red_upper - red_lower) <= 1:
|
||
|
break
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
solution = euler_100()
|
||
|
print("e100.py: " + str(solution))
|
||
|
assert(solution == 756872327473)
|
||
|
|