Sunday Times Teaser 2582 – Anyone for Tennis?
by Angela Newing
Published: 18 March 2012 (link)
The girls of St Trinian’s choose two games from the four on offer. In Felicity’s gang of four, no game was chosen by both Daphne and Erica; Chloe and Miss Brown chose lacrosse; Miss Smith chose netball; and only Miss Jones excluded hockey. In Harriet’s gang of four, Clara, Debbie and Ellen all chose netball but only one of the four chose hockey. To avoid having two girls with the same first name initial in any one game, one of the girls in the second group (but not Debbie) moved from one game to another. This meant that there was an odd number of these girls playing each game.
Which of the eight girls played tennis?
One Comment
Leave one →
-
Brian Gladman permalink123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147from itertools import combinations, permutations, productfrom collections import defaultdictgames = ( 'Hockey', 'Lacrosse', 'Netball', 'Tennis' )surnames = ( 'Brown', 'Smith', 'Jones', 'Who?' )# Felicity's and Harriet's groupsfs_group = ( 'Chloe', 'Daphne', 'Erica', 'Felicity' )hs_group = ( 'Clara', 'Debbie', 'Ellen', 'Harriet' )# the possible pairings of two games from fourg_pairs = [frozenset(p) for p in combinations(games, 2)]# map the surnames to Felicity's group's first namesfor sur in permutations(surnames):sur_to_f = dict(zip(sur, fs_group))# Chloe does not have the surname Brownif sur_to_f['Brown'] == 'Chloe':continue# try possible pairs of games for Felicity's groupfor fgp in product(g_pairs, repeat=4):# map Felicity's group to game pairsfg_to_games = dict(zip(fs_group, fgp))# no game was chosen by both Daphne and Ericaif fg_to_games['Daphne'] & fg_to_games['Erica']:continue# Chloe and Miss Brown chose Lacrosseif not ('Lacrosse' in fg_to_games['Chloe'] and'Lacrosse' in fg_to_games[sur_to_f['Brown']]):continue# Miss Smith chose Netballif 'Netball' not in fg_to_games[sur_to_f['Smith']]:continue# only Ms Jones excluded Hockeyif 'Hockey' in fg_to_games[sur_to_f['Jones']]:continueif not all('Hockey' in g2 for fn, g2 in fg_to_games.items()if fn != sur_to_f['Jones']):continue# try possible pairs of games for Harriet's groupfor hgp in product(g_pairs, repeat=4):# map Harriet's group to game pairshg_to_games = dict(zip(hs_group, hgp))# Clara, Debbie and Ellen all chose Netballif not ('Netball' in hg_to_games['Clara'] and'Netball' in hg_to_games['Debbie'] and'Netball' in hg_to_games['Ellen']):continue# only one of the four chose Hockeyif sum(1 for p, gs in hg_to_games.items()if 'Hockey' in gs) != 1:continue# now compile player lists for each of the four gamesg_to_pl = defaultdict(list)for i in (0, 1):for p in (fs_group, hs_group)[i]:g1, g2 = (fg_to_games, hg_to_games)[i][p]g_to_pl[g1] += [p]g_to_pl[g2] += [p]# there must be only two games with an even number of players# (which will become odd after the move of one player)g_even = [g for g, p in g_to_pl.items() if not len(p) % 2]if len(g_even) != 2:continue# now find the duplicated first letters in the names# of players for each gamedup_ltrs = dict()for g, p in g_to_pl.items():fl = ''.join(x[0] for x in p)dup_ltrs[g] = set(ch for ch in set(fl) if fl.count(ch) > 1)# if two or more games have duplicates we can't remove# them by moving one player from one game to anotherif len([x for x in dup_ltrs.values() if x]) != 1:continue# the same applies if any game has two or more duplicatesif any(len(x) > 1 for x in dup_ltrs.values()):continue# the game with duplicates must have an even number of# of players since the move must leave an odd numberg_frm, = (g for g in g_to_pl if dup_ltrs[g])if len(g_to_pl[g_frm]) % 2:continue# the move is to the other game with an even number of# playersg_to = [g for g in g_even if g != g_frm][0]# select a player to movefor plr in g_to_pl[g_frm]:# she must have a duplicated first letter and be from# Harriet's group (but not Debbie)if (plr[0] in dup_ltrs[g_frm] andplr in set(hs_group).difference(['Debbie'])):# avoid moves that will create a duplicate first letterif plr[0] not in ''.join(x[0] for x in g_to_pl[g_to]):# copy the 'game to players' map and then update the# copy to account for the move of the playerg_to_p2 = g_to_pl.copy()g_to_p2[g_frm] = [p for p in g_to_pl[g_frm] if p != plr]g_to_p2[g_to] += [plr]# now output a full description of the solutiont = {v:k for k, v in sur_to_f.items()}print("Felicity's Group:")for n in fs_group:print(' {:15}: {}, {}'.format(n + ' ' + t[n],*tuple(sorted(fg_to_games[n]))))print("nHarriet's Group:")for n in hs_group:print(' {:15}: {}, {}'.format(n,*tuple(sorted(hg_to_games[n]))))print('nGames (before move):')for g in sorted(g_to_pl):ss = ' {:8s}: '.format(g)for p in sorted(g_to_pl[g]):ss += ((p + ' ' + t[p]) if p in fs_group else p) + ', 'print(ss[:-2])print('nGames after {} moved from {} to {}:'.format(plr, g_frm, g_to))for g in sorted(g_to_p2):ss = ' {:8s}: '.format(g)for p in sorted(g_to_p2[g]):ss += ((p + ' ' + t[p]) if p in fs_group else p) + ', 'print(ss[:-2])