Sunday Times Teaser 2969 – Slide Rules
by Stephen Hogg
Published August 18 2019 (link)
Using her ordinary 15cm ruler and Zak’s lefthanded version (numbers 1 to 15 reading right to left) Kaz could display various fractions. For instance, putting 5 on one ruler above 1 on the other ruler, the following set of fractions would be displayed: 5/1, 4/2, 3/3, 2/4 and 1/5. Zak listed the fifteen sets starting from “1 above 1” up to “15 above 1”.
Kaz chose some fractions with values less than one from Zak’s sets (using just the numerals 1 to 9, each once only in her selection). Of these, two were in simplest form, one of which had consecutive numerator and denominator. Zak correctly totalled Kaz’s selection, giving the answer as a fraction in simplest form. Curiously, the answer’s numerator and denominator were both palindromic.
Give Zak’s answer.

Brian Gladman permalink1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253from math import gcd# find the set of digits in an integer in 1..15set_dg = lambda x: {x} if x < 10 else {1, x % 10}# return the sum of two fractions (each tuples)sum_2f = lambda a, b: (a[0] * b[1] + a[1] * b[0], a[1] * b[1])# find fractions (less than one) that are generated by the# overlapping rulers and which contain no duplicate digitsfr = []for i in range(2, 16):for n, d in zip(range(i // 2, 0, 1), range((i + 3) // 2, i + 1)):if not ({n, d} & {10, 11} or set_dg(n) & set_dg(d)):fr.append((n, d))fr.sort(key=lambda x:x[0]/x[1])# generate sets of fractions that among them use each of the digits# 1..9 exactly once and in which two are in their lowest terms and# one of these has a numerator and denominator that differ by onedef solve(fr, dgts=set(range(1, 10)), fs=[]):if not dgts:# two fractions must be in simple termssf = tuple((n, d) for n, d in fs if gcd(n, d) == 1)if len(sf) == 2:# ... one with a numerator and denominator differing by oneif (sf[0][1] == sf[0][0] + 1) ^ (sf[1][1] == sf[1][0] + 1):yield fselse:for i, (n, d) in enumerate(fr, 1):dg_nd = set_dg(n)  set_dg(d)if dg_nd <= dgts:yield from solve(fr[i:], dgts  dg_nd, fs + [(n, d)])sols = []for i, fs in enumerate(solve(fr), 1):sols.append(fs)# sum the fractions and put the sum in its lowest termsn, d = 0, 1for f in fs:(n, d) = sum_2f((n, d), f)g = gcd(n, d)n, d = str(n // g), str(d // g)# look for a result in which the numerator and# the denominator are both palindromesif n == n[::1] and d == d[::1]:print(f"{n}/{d} {fs}")# output all compliant sequences of fractionsfor i, fs in enumerate(sorted(sols), 1):print(f"{i:2} {sorted(fs, key=lambda x:x[0]/x[1])}")

Erling Torkildsen permalink12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758from math import gcddef Z(a, b, c, d, e, f, g, i):hi = 10 + i# number of fractions in simplest form == 2?t1 = ((gcd(a, b) == 1) + (gcd(c, d) == 1) +(gcd(e, f) == 1) + (gcd(g, hi) == 1)) == 2# numerator and denominator consecutive?t2 = ((b == a + 1) + (d == c + 1) +(f == e + 1) + (hi == g + 1)) == 1N = (a * d * f * hi + c * b * f * hi +e * b * d * hi + g * b * d * f)D = b * d * f * hi# return numerator and denominator in simplest# form and the results of testsreturn (N // gcd(N, D), D // gcd(N, D), t1, t2)# is n a palindrome?def P(n):s = str(n)return len(s) > 1 and s == s[::1]# candidatesXs = set()for a in range(2, 10):for b in range(a + 1, 10):for c in range(2, 10):if c in (a, b):continuefor d in range(c + 1, 10):if d in (a, b):continuefor e in range(2, 10):if e in (a, b, c, d):continuefor f in range(e + 1, 10):if f in (a, b, c, d):continuefor g in range(2, 10):if g in (a, b, c, d, e, f):continuefor i in range(2, 6):if i in (a, b, c, d, e, f, g):continuep, q, t1, t2 = Z(a, b, c, d, e, f, g, i)if P(p)and P(q) and t1 and t2:Xs.add((p, q))if len(Xs) > 1:print("Multiple solutions..")else:X, = Xsprint(f"Zak’s answer: {X[0]}/{X[1]}")