Teaser 2873: Circular logic
From The Sunday Times, 15th October 2017 [link] [link]
Ten of us (me [Ian], 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?
[teaser2873]
Jim Randell 9:26 am on 8 March 2022 Permalink |
We can look for viable 12-seat layouts, and then remove Ari and Ira to give a 10-seat layout, which we can check is viable.
This Python program runs in 88ms.
Run: [ @replit ]
from enigma import (update, ordered, diff, join, printf) # implement a circular list (see Tantalizer 496) class CircularList(list): def __getitem__(self, i): return list.__getitem__(self, i % len(self)) def copy(self): # list.copy() returns a list(), so re-wrap it return self.__class__(list.copy(self)) # find names in <ns> that can be opposite/adjacent to <ps> def valid(ns, ps): # find disallowed initials and anagrams xis = set(p[0] for p in ps if p is not None) xas = set(ordered(*p) for p in ps if p is not None) for n in ns: if n[0] in xis or ordered(*n) in xas: continue yield n # place names <ns> in table <t> def place(t, ns): # are we done? if not ns: if t[1] < t[-1]: yield t else: # find the next unoccupied place i = t.index(None) # choose someone to occupy it for n in valid(ns, {t[i + 6], t[i - 1], t[i + 1], t[i - 2], t[i + 2]}): yield from place(update(t, [(i, n)]), ns.difference([n])) # create a 12-place table t = CircularList([None] * 12) # place IAN at position 0 and ROLAND in position 6 t[0] = "IAN" t[6] = "ROLAND" # the remaining people people = { "ALICE", "ARNOLD", "CARLA", "CELIA", "CLARA", "INA", "RONA", "RONALD", "ARI", "IRA" } # find possible 12 place tables for t12 in place(t, people): # now remove ARI and IRA to give a 10 place table t = CircularList(diff(t12, {"ARI", "IRA"})) # check ROLAND is no longer opposite IAN if t[5] == "ROLAND": continue # check t is a valid table if not all(n in valid([n], {t[i + 5], t[i - 1], t[i + 1], t[i - 2], t[i + 2]}) for (i, n) in enumerate(t)): continue # output solution printf("{t12} <- {t10}", t12=join(t12, sep=" ", enc="[]"), t10=join(t, sep=" ", enc="[]")) for x in ["ALICE", "CELIA"]: opp = t[t.index(x) + 5] printf("-> ({x} <-> {opp})") printf()Solution: Rona ended up opposite Alice. Ira ended up opposite Celia.
Here is a possible layout of the 12 seats (going round the table, listing opposites):
CARLA and CLARA can swap positions to give a second layout.
And the tables can be mirrored (go round the table anti-clockwise, instead of clockwise) to give further viable layouts.
LikeLike