Teaser 2775: Strictly not
From The Sunday Times, 29th November 2015 [link] [link]
Four celebrities entered a dance competition. Five judges each shared out their eight marks among the four dancers, with each getting a non-zero whole number. Each judge split the eight marks in a different way and then allocated them as follows. Amanda’s marks to Lana and Natasha added to the same total as Barry’s marks to Madge and Paula. Barry gave more marks to Madge than to any other dancer, Charles gave more to Paula than to any other, and Doris gave more to Natasha than to any other. Lana scored more from Edna than from Amanda. All dancers had the same total so the head judge’s scores were used, giving a winner and runner-up.
Who was the head judge, who was the winner and who was the runner-up?
[teaser2775]
Jim Randell 8:51 am on 9 February 2021 Permalink |
Each of the 5 judges gives out 8 points, so 40 points are awarded in total. And there are 4 dancers, and they all receive the same total number of points. So each dancer receives 10 points in total.
Each judge awards a non-zero number of points to each dancer, so the points awarded are between 1 and 5.
I used the [[
SubstitutedExpression]] solver from the enigma.py library to find possible collections of points awarded by the judges, and the scores are then examined to determine which judges scores identify a clear winner and runner up.The following run file executes in 80ms.
Run: [ @replit ]
from enigma import (SubstitutedExpression, irange, seq_all_different, ordered, printf) # consider the points given: # # Lana # | Madge # | | Natasha # | | | Paula # Amanda: A B C D = 8 # Barry: E F G H = 8 # Charles: I J K L = 8 # Doris: M N P Q = 8 # Edna: R S T U = 8 # = = = = # 10 10 10 10 # check the splits are all different check_splits = lambda *xs: seq_all_different(ordered(*x) for x in xs) # construct the alphametic problem p = SubstitutedExpression([ # each judge gave out 8 points "A + B + C + D = 8", "E + F + G + H = 8", "I + J + K + L = 8", "M + N + P + Q = 8", "R + S + T + U = 8", # points were split in a different way by each judge "check_splits((A, B, C, D), (E, F, G, H), (I, J, K, L), (N, M, P, Q), (R, S, T, U))", # "A's marks to L and N had the same sum as B's marks to M and P" "A + C == F + H", # "B gave more marks to M than to any other" "max(E, G, H) < F", # "C gave more to P than to any other" "max(I, J, K) < L", # "D gave more to N than to any other" "max(M, N, Q) < P", # "L scored more from E than from A" "R > A", # all dancers had the same total (= 10) "A + E + I + M + R = 10", "B + F + J + N + S = 10", "C + G + K + P + T = 10", "D + H + L + Q + U = 10", ], distinct=(), digits=irange(1, 5), # points are in the range 1-5 env=dict(check_splits=check_splits), # answer is the scores from each judge answer="((A, B, C, D), (E, F, G, H), (I, J, K, L), (M, N, P, Q), (R, S, T, U))", denest=-1, # [CPython] work around statically nested block limit ) # solve the puzzle, and output solutions (judges, dancers) = ("ABCDE", "LMNP") for (_, scores) in p.solve(verbose=0): # look for scores that differentiate 1st and 2nd place for (j, ss) in zip(judges, scores): printf("{j}: {ss}\\") (p1, p2, p3, p4) = sorted(ss, reverse=1) if p1 > p2 > p3: (d1, d2) = (dancers[ss.index(p)] for p in (p1, p2)) printf(" -> head judge; 1st = {d1}, 2nd = {d2}\\") printf() printf()Solution: Doris was the head judge. Natasha was the winner. Lana was the runner-up.
The scores were allocated as follows (L, M, N, P):
There are only 5 different (unordered) ways to divide a score of 8 between 4 dancers, and only one of them (4, 2, 1, 1) gives a clear 1st and 2nd place.
LikeLike
Frits 9:26 pm on 9 February 2021 Permalink |
from collections import defaultdict # consider the points given: # # Lana # | Madge # | | Natasha # | | | Paula # Amanda: A B C D = 8 # Barry: E F G H = 8 # Charles: I J K L = 8 # Doris: M N P Q = 8 # Edna: R S T U = 8 # = = = = # 10 10 10 10 M = 5 # number of rows N = 4 # number of columns # decompose number <t> into <k> positive numbers from <ns> # so that sum(<k> numbers) equals <t> def decompose(t, k, ns, s=[]): if k == 1: if t in ns: yield s + [t] else: for (i, n) in enumerate(ns): if not(n + k - 2 < t): break #yield from decompose(t - n, k - 1, ns[i:], s + [n]) yield from decompose(t - n, k - 1, ns, s + [n]) # combine rows of dictionary <d> # so that every column total equals <t> def combineRows(t, k, d, s=[]): if k == 1: remaining = [t - sum(x) for x in zip(*s)] if remaining in d[0]: yield s + [remaining] else: for row in d[k - 1]: # for each column ... for j in range(N): # .. sum already processed numbers already = sum([0 if len(s) == 0 else x[j] for x in s]) # and check if there is room for remaining rows if not(row[j] + already + k - 2 < t): already = -1 # skip this row break if already > -1: yield from combineRows(t, k - 1, d, s + [row]) types = [] d_rows = defaultdict(list) # create dictionary of possible rows for each type of row # the points awarded are between 1 and 5 for x in decompose(8, N, range(1, 6)): sortx = sorted(x) if sortx in types: type = types.index(sortx) else: type = len(types) types.append(x) # append possible row d_rows[type] += [x] # combine rows so that column total always equals 10 for rows in combineRows(10, M, d_rows): testB, testC, testD = -1, -1, -1 # validate rows for i, r in enumerate(rows): sr = sorted(r) # check if maximum value is unique if sr[-1] > sr[-2]: if sr[-1] == r[1]: # testB : "max(E, G, H) < F", testB = i elif sr[-1] == r[3]: # testC : "max(I, J, K) < L", testC = i elif sr[-1] == r[2]: # testD : "max(M, N, Q) < P", testD = i if -1 in {testB, testC, testD}: continue # get the other rows ix_oth = [x for x in range(M) if x not in {testB, testC, testD}] # "R > A" if rows[ix_oth[0]][0] < rows[ix_oth[1]][0]: testA = ix_oth[0]; testE = ix_oth[1] elif rows[ix_oth[0]][0] > rows[ix_oth[1]][0]: testE = ix_oth[0]; testA = ix_oth[1] else: continue # "A + C == F + H" if rows[testA][0] + rows[testA][2] != rows[testB][1] + rows[testB][3]: continue # the head judge's scores were used, giving a winner and runner-up judges, dancers = "ABCDE", "LMNP" for i, r in enumerate(rows): sr = sorted(r) if sr[1] < sr[2] < sr[3]: print(f"head judge: {judges[i]} ") print(f"winner : {dancers[r.index(sr[3])]}") print(f"runner up : {dancers[r.index(sr[2])]}") print() for r in rows: print(r)LikeLike