Sunday Times Teaser 2873 – Circular Logic
by Ian Gilchrist
Published October 15 2017 (link)
Ten of us (me, Alice, Arnold, Carla, Celia, Clara, Ina, Rona, Ronald and Roland) were sitting equally-spaced around a circular table. None of us was directly opposite or next to anyone whose name was an anagram of theirs, or between two people whose names were anagrams of each other. The same applied when looking at the initial letters of the names.
Then Ari and Ira joined us. We found two extra chairs and all budged up to make two spaces. With the twelve of us equally-spaced around the circular table all the above facts remained true. I was now opposite a different person, Roland.
Who from the twelve was then directly opposite Alice? And who was opposite Celia?
One Comment
Leave one →
-
Brian Gladman permalink123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475from itertools import combinations, productfrom collections import defaultdictn10 = ('Ian', 'Alice', 'Arnold', 'Carla', 'Celia', 'Clara', 'Ina', 'Rona', 'Ronald', 'Roland')n3 = ('Ari', 'Ira')# map each name to a set of compatible namescp = defaultdict(set)for a, b in combinations(n10 + n3, 2):if not (a[0] == b[0] or set(a.lower()) == set(b.lower())):cp[a].add(b)cp[b].add(a)# find a sequence of <n> names from <names> that can be arranged# around a circle such that names are compatible with adjacent and# opposite names and names either side of a name are compatibledef solve(seq, n, names):ln = len(seq)if ln == n:# make sure that the chain is circular and avoid# counterclockwise duplicatesif seq[-1] in cp[seq[1]] and seq[1] > seq[-1]:yield seqelse:# check each remaining name in the next positionfor nm in names:# check the name is compatible with its placed neighbourif nm not in cp[seq[-1]]:continue# ... and its placed neighbour two awayif ln > 2 and nm not in cp[seq[-2]]:continue# ... and the name oppositeif ln >= n // 2 and nm not in cp[seq[-(n // 2)]]:continue# place the name and continue to the next positionyield from solve(seq + [nm], n, names.difference([nm]))for seq in solve([ 'Ian'], 10, set(n10).difference(['Ian'])):# the opposite name cannot be 'Roland' because it changesif seq[5] != 'Roland':# try the two additional names in either of two chosen positionsfor n1, n2 in (('Ari', 'Ira'), ('Ira', 'Ari')):# choose a position to insert the first namefor j in range(1, 13):# ... and insert the first names = seq.copy()s.insert(j, n1)# choose a position to insert the second namefor k in range(1, j + 1):# ... and insert itt = s.copy()t.insert(k, n2)# check that opposite names are still compatibleif any(t[i + 6] not in cp[t[i]] for i in range(6)):continue# check that adjacent names are still compatibleif any(t[(i + 1) % 12] not in cp[t[i]] for i in range(12)):continueif any(t[(i - 1) % 12] not in cp[t[i]] for i in range(12)):continue# check that 'two apart' names are still compatibleif any(t[(i + 1) % 12] not in cp[t[i - 1]] for i in range(1, 12)):continueif t[6] == 'Roland':# find opposites for Alice and Celiaa2 = t[(t.index('Alice') + 6) % 12]c2 = t[(t.index('Celia') + 6) % 12]print(f'Alice -> {a2}, Celia -> {c2}'f' ({", ".join(seq)}), ({", ".join(t)}).')