Sunday Times Teaser 2902 – Birthdays 2018
by Graham Smithers
Published May 6 2018 (link)
Several friends have birthdays on different days in 2018, each birthday being given as the weekday, the day of the month and the month with the weekday and the month given in alphabetic form (e.g. Sunday 6 May). The weekday and the month are then converted into sets of numbers by converting each letter into upper case and then replacing A by 1, B by 2, C by 3, …, Z by 26.
The number of friends is as large as possible and, for each friend, the day of the month occurs in the number sets for both the weekday and the month and this is also the only number common to both.
How many friends are there and what is the largest number of clear days between consecutive birthdays in 2018?
(Note: this description is a modified version of the original text published by the Sunday Times: see link)
-
Brian Gladman permalink12345678910111213141516171819202122232425262728293031323334353637383940414243from calendar import month_name, day_namefrom datetime import date, timedeltaonly_2018_birthdays = True# output a date for date <d> + <i> daysdmy = lambda d, i: (d + timedelta(i)).strftime('%a %d %b %Y')# for converting names to numbersalp = '_ABCDEFGHIJKLMNOPQRSTUVWXYZ'# for storing birthdaysbdays = []# set start and end dates for 2018g1 = date(day=1, month=1, year=2018).toordinal()g2 = date(day=1, month=1, year=2019).toordinal()# consider each day in 2018for g in range(g1, g2):# find the day and monthd = date.fromordinal(g)# convert the weekday and month names into sets of numbersws = {alp.index(x.upper()) for x in day_name[d.weekday()]}ms = {alp.index(x.upper()) for x in month_name[d.month]}# the pairs formed from (weekday, day of month, month) each# share only one common numberif (ws & ms) == {d.day}:bdays.append(d)# the number of friendsfriends = len(bdays)# add this line if the first 2019 birthday should be considered# in finding the longest consecutive sequences of non-birthdaysif not only_2018_birthdays:bdays.append(bdays[0].replace(year=2019))# find the maximum consecutive non-birthdays (and adjacent birthdays)mx = max(((y - x).days - 1, x, y) for x, y in zip(bdays, bdays[1:]))print(f'There are {friends} friends and a maximum of {mx[0]} 'f'consecutive non-birthdays ({dmy(mx[1], 1)} .. {dmy(mx[2], -1)}).')