Tagged: by: Robert Gray Toggle Comment Threads | Keyboard Shortcuts

  • Unknown's avatar

    Jim Randell 9:30 am on 7 April 2022 Permalink | Reply
    Tags: by: Robert Gray   

    Brain-Teaser 910: The Teaser Club 

    From The Sunday Times, 30th December 1979 [link]

    “The Teaser Club was formed in the summer of 1969”, the secretary of the Chub told me. “We held our Inaugural meeting then. A president and a secretary were appointed, and a constitution was drawn up. One rule of the Club is that each member must send a Christmas card to every other member. Each card, as you may guess, carries a Teaser as well as Christmas greetings”.

    The membership increased every year”, he continued, “indeed, in 1970, we sent 330 more cards than we did in 1969”.

    “How many were sent in 1978?”, I asked.

    “We sent 330 more than in 1977”, the secretary replied with a smile.

    “And how many did you send in 1977?”, I persisted.

    “By a strange coincidence”, he replied, “it was 330 more than in 1976”.

    “Thank you for your information”, I said. “I see now why you call it the Teaser Club”.

    How many Christmas cards were sent in 1975?

    This puzzle is included in the book The Sunday Times Book of Brainteasers (1994). The puzzle text above is taken from the book.

    [teaser910]

     
    • Jim Randell's avatar

      Jim Randell 9:31 am on 7 April 2022 Permalink | Reply

      If there are n members of the club, then the number of cards send is s(n) = n(n − 1).

      This Python program looks for pairs of possible s(n) values that differ by 330. And then looks for two pairs which chain together (for the 1976, 1977, 1978 membership.

      We then look for possible lower values (the membership must grow by at least 1 member a year) for the 1969, 1970 membership.

      Together these give us upper and lower bounds on the 1975 membership, from which we can determine the number of cards sent.

      It runs in 55ms.

      Run: [ @replit ]

      from enigma import (irange, inf, subsets, printf)
      
      # record s[n] = number of cards sent by n members
      s = [0]
      for n in irange(1, inf):
        t = n * (n - 1)
        if t - s[-1] > 330: break
        s.append(t)
      
      # find terms that differ by 330, record by index
      d = dict()
      for ((i, x), (j, y)) in subsets(enumerate(s), size=2):
        if y - x == 330:
          d[i] = j
          printf("[s[{i}] = {x} -> s[{j}] = {y}]")
      
      # look for indices i, j, k such that d[i] = j and d[j] = k
      for (i, j) in d.items():
        k = d.get(j)
        if k is None: continue
        printf("1976 = {i}; 1977 = {j}; 1978 = {k}")
      
        # and look for 1969, 1970 valules
        for (a, b) in d.items():
          if b + 6 > i: continue
          printf("-> 1969 = {a}; 1970 = {b}")
      
          # calculate 1975 values
          for g in irange(b + 5, i - 1):
            printf("--> 1975 = {g}; cards = {x}", x=s[g])
      

      Solution: 552 Christmas cards were sent in 1975.

      Like

  • Unknown's avatar

    Jim Randell 7:15 am on 14 October 2021 Permalink | Reply
    Tags: by: Robert Gray   

    Brain-Teaser 879: Seven criminals 

    From The Sunday Times, 11th June 1978 [link]

    The instructor at the police training college spoke to the six constables in his class in these words:

    “You have been studying full-face photographs of seven criminals whom we are calling P, Q, R, S, T, U and V. Now l am going to show you one photograph, taken in profile, of each criminal, and you have to write down their names in the
    order in which I present them.”

    This was done and the constables handed in the following
    six answers:

    1. P Q R S T U V
    2. P Q R U T S V
    3. P S U V R T Q
    4. P S Q U R T V
    5. P U R V T S Q
    6. R P U Q T S V

    “I am pleased to see that each criminal has been correctly identified by at least one of you”, said the instructor. “And I note that you all have a different number of correct answers and so I can give out the prizes”.

    In what order were the photographs presented?

    This puzzle is included in the book The Sunday Times Book of Brain-Teasers: Book 1 (1980). The puzzle text above is taken from the book.

    [teaser879]

     
    • Jim Randell's avatar

      Jim Randell 7:16 am on 14 October 2021 Permalink | Reply

      It is straightforward to check all possible arrangements.

      This Python program runs in 87ms.

      Run: [ @replit ]

      from enigma import subsets, seq_all_different, join, printf
      
      # the six answers
      ans = [
        'PQRSTUV',
        'PQRUTSV',
        'PSUVRTQ',
        'PSQURTV',
        'PURVTSQ',
        'RPUQTSV',
      ]
      
      # count number of items in correct position
      correct = lambda xs, ys: sum(x == y for (x, y) in zip(xs, ys))
      
      # consider possible orderings
      for ss in subsets('PQRSTUV', size=len, select="P"):
        # how many are in the correct position?
        pos = list(correct(xs, ss) for xs in ans)
        if not seq_all_different(pos): continue
        # check each item is correct in one of the answers
        if not all(any(xs[i] == x for xs in ans) for (i, x) in enumerate(ss)): continue
        # output solution
        printf("{ss} -> {pos}", ss=join(ss, sep=" ", enc="()"))
      

      Solution: The photographs were presented in the following order: R, P, U, V, T, S, Q.

      And the number of photographs correctly identified by the constables were: 1, 2, 3, 0, 4, 5.

      There is only a single solution without the condition that each criminal was identified correctly by (at least) one of the constables. But we see that the last constable got Q and V wrong (and the rest right), but the penultimate constable got these two right, so each miscreant was identified correctly by one of the constables.

      Like

    • Frits's avatar

      Frits 10:12 am on 15 October 2021 Permalink | Reply

      Borrowing from above program and the solve() function in Teaser 3080 (One of a kind).
      The program runs in 2ms.

        
      # find members of each set, such that each member is used exactly once
      def solve(ss, ns=[], ds=set()):
        # are we done?
        if not(ss):
          yield ns
        else:
          # choose an element from the next set
          for n in ss[0]:
            if not(ds.intersection(n)):
              yield from solve(ss[1:], ns + [n], ds.union(n))
      
      # count number of items in correct position
      correct = lambda xs, ys: sum(x == y for (x, y) in zip(xs, ys))
      
      # the six answers
      ans = [
        'PQRSTUV',
        'PQRUTSV',
        'PSUVRTQ',
        'PSQURTV',
        'PURVTSQ',
        'RPUQTSV',
      ]
      
      nr_criminals = len(ans[0])
      nr_answers = len(ans)
      
      # make list of used values
      lst = [set(a[i] for a in ans) for i in range(nr_criminals)]
      
      for ss in solve(lst):
        pos = set(correct(xs, ss) for xs in ans)
        if len(pos) != nr_answers: continue
        
        print(f"{', '.join(ss)} --> {pos}")
      

      Like

      • Jim Randell's avatar

        Jim Randell 2:57 pm on 15 October 2021 Permalink | Reply

        You can use the following to turn a collection of rows into the corresponding collection of columns:

        cols = zip(*rows)
        

        (And [[ unzip() ]] is an alias for this in enigma.py).

        We can also simplify the way the [[ solve() ]] function operates. (I’ve renamed it [[ select() ]]).

        from enigma import unzip, seq_all_different, join, printf
        
        # the six answers
        ans = [
          'PQRSTUV',
          'PQRUTSV',
          'PSUVRTQ',
          'PSQURTV',
          'PURVTSQ',
          'RPUQTSV',
        ]
        
        # select distinct elements from each set in list of sets <ss>
        def select(ss, rs=[]):
          # are we done?
          if not ss:
            yield rs
          else:
            for x in ss[0].difference(rs):
              yield from select(ss[1:], rs + [x])
        
        # count number of items in correct position
        correct = lambda xs, ys: sum(x == y for (x, y) in zip(xs, ys))
        
        # each photograph was identified correctly in at least one answer
        # so the the correct value occurs in each column
        
        # consider possible correct orderings
        for ss in select(list(set(col) for col in unzip(ans))):
          # how many are in the correct position?
          pos = list(correct(xs, ss) for xs in ans)
          if not seq_all_different(pos): continue
          # output solution
          printf("{ss} -> {pos}", ss=join(ss, sep=" ", enc="()"))
        

        I did try a version of [[ select() ]] that chooses from the column with the smallest number of values available, but it is no advantage on a problem of this size.

        Like

c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel
Design a site like this with WordPress.com
Get started