Tagged: flawed Toggle Comment Threads | Keyboard Shortcuts

  • Unknown's avatar

    Jim Randell 5:53 pm on 23 December 2021 Permalink | Reply
    Tags: , flawed   

    Teaser 3092: A Christmas Carol 

    From The Sunday Times, 26th December 2021 [link] [link]

    A Christmas Carol was published on 19/12/1843, when Bob Cratchit was in his forties, almost seven years after Jacob Marley’s death on Christmas Eve. On Marley’s last Christmas Day, a working day for them all as always, Scrooge said to Cratchit and Marley: “We three will work the same dates next year as this year, except that I’ll cover Cratchit’s birthday so he can have the day off, since Marley never works on his”. On Boxing Day, Scrooge decided to allocate extra work dates for next year to anyone whose number of work dates was going to be below the average of the three of them, bringing them up to exactly that average. Daily, up to and including New Year’s Eve, Scrooge repeated this levelling-up to the new average, never needing fractions of a day.

    What was Bob Cratchit’s full date of birth?

    In the book The Sunday Times Teaser Book 2 (2023), the “levelling-up” process is described as follows:

    … Scrooge decided to allocate extra work dates for the next year to the one whose number of work dates was going to be below the average of the three of them, bringing him up to exactly that average. Daily, up to and including New Year’s Eve, Scrooge repeated this levelling-up for that person to the new average, never needing fractions of a day.

    Which is intended to indicate that only one of the three is “levelled-up” each time the process is applied.

    [teaser3092]

     
    • Jim Randell's avatar

      Jim Randell 5:55 pm on 23 December 2021 Permalink | Reply

      I’m not sure I understand how this is meant to work as a puzzle.

      If Cratchit is in his forties on 1843-12-19, then he was born sometime between 1794 and 1803.

      And, if Marley died on 1836-12-24, his last Christmas Day would be 1835-12-25, so Scrooge was planning the dates for 1836.

      All we know for sure (for the initial schedule) is that they all work every Christmas Day, Marley never works on his birthday, and Scrooge will work on Cratchit’s birthday in 1836 but Cratchit won’t.

      So the number of possible workdays initially scheduled for 1836 is: Scrooge 2-366, Cratchit 1-365, Marley 1-365.

      I found 3429 initial assignments of numbers of work days in 1836 that would allow Scrooge to perform his procedure 6 times.

      For example if the initial number of allocated work days is (99, 268, 308) we have:

      26th: (99, 268, 308), mean = 225 → (225, 268, 308)
      27th: (225, 268, 308), mean = 267 → (267, 268, 308)
      28th: (267, 268, 308), mean = 281 → (281, 281, 308)
      29th: (281, 281, 308), mean = 290 → (290, 290, 308)
      30th: (290, 290, 308), mean = 296 → (296, 296, 308)
      31st: (296, 296, 308), mean = 300 → (300, 300, 308)

      But there doesn’t seem to be any specified conditions to allow us to narrow down these numbers to a set that would allow us to determine a specific date for Cratchit’s birthday.

      However, there is a particular date that suggests itself as the only one of the candidate birthdates that has a certain property, so maybe that is the required answer. And it is the same unique date that we get if we make certain assumptions about the behaviour of Scrooge.

      Solution: [See below]

      Like

      • Jim Randell's avatar

        Jim Randell 10:22 am on 1 January 2022 Permalink | Reply

        The published puzzle text is flawed.

        Apparently the setter intended that only one of the three would be “levelled up” each time the process is applied.

        This leads to a single levelling up process:

        26th: (1, 365, 366), mean = 244 → (244, 365, 366)
        27th: (244, 365, 366), mean = 325 → (325, 365, 366)
        28th: (325, 365, 366), mean = 352 → (352, 365, 366)
        29th: (352, 365, 366), mean = 361 → (361, 365, 366)
        30th: (361, 365, 366), mean = 364 → (364, 365, 366)
        31st: (364, 365, 366), mean = 365 → (365, 365, 366)

        So, before the “levelling up” process started the work days allocated were 1, 365, 366.

        Scrooge must be 366, as he is working an extra day compared to 1835, and there were 365 days in 1835. The extra day worked is the leap day in 1836, and this must also be Cratchit’s birthday.

        Cratchit must be 365, as Marley did not work on his birthday in 1835.

        Hence, Marley must be the 1. He only worked Christmas day.

        So the intended answer was:

        Solution: Bob Cratchit was born on 29th February 1796.

        And this was the answer I suspected, as it was the only date with a certain property in the required range (i.e. the only 29th February), without worrying about the “levelling up” stuff at all.

        Like

  • Unknown's avatar

    Jim Randell 11:18 am on 16 December 2021 Permalink | Reply
    Tags: , flawed   

    Teaser 2844: Children’s children 

    From The Sunday Times, 26th March 2017 [link] [link]

    The head teacher’s retirement celebration was attended by many former pupils. These included Adam, Brian, Colin and David, whose sons and grandsons had also attended the school – actually different numbers of grandsons for each of them, with Adam having the most. Their sons were Eric, Fred, George, Harry and Ivan, and the sons of the sons were John, Keith, Lawrence, Michael, Norman and Oliver.

    Altogether Adam and Brian had sons Eric, Fred and one other; altogether Adam and Colin had sons George and one other; altogether Eric, George and Harry had sons Keith, Michael, Norman and one other; and altogether Harry and Ivan had sons Lawrence, Norman and one other.

    The retirement gift was presented by the fathers of John’s and Oliver’s fathers.

    Who were they?

    As stated there are multiple solutions to this puzzle.

    This puzzle was not included in the published collection of puzzles The Sunday Times Brainteasers Book 1 (2019).

    There are now 600 puzzles available on S2T2.

    [teaser2844]

     
    • Jim Randell's avatar

      Jim Randell 11:19 am on 16 December 2021 Permalink | Reply

      As stated the puzzle has multiple solutions.

      The following Python program builds the 8 possible family trees that fit the described situation.

      It runs in 85ms.

      Run: [ @replit ]

      from enigma import (subsets, peek, product, map2str, join, printf)
      
      # map ks to vs
      def make_map(ks, vs):
        for ss in subsets(ks, size=len(vs), select='M'):
          d = dict((k, list()) for k in ks)
          for (k, v) in zip(ss, vs):
            d[k].append(v)
          yield d
      
      # find viable father -> sons mappings
      def check_fs(fs):
      
        # "A, B have sons E, F and one other"
        s = fs['A'] + fs['B']
        if not (len(s) == 3 and 'E' in s and 'F' in s): return False
      
        # "A, C have sons G and one other"
        s = fs['A'] + fs['C']
        if not (len(s) == 2 and 'G' in s): return False
      
        # looks OK
        return True
      
      # collect viable maps
      ffs = list(fs for fs in make_map('ABCD', 'EFGHI') if check_fs(fs))
      
      # find viable son -> grandsons maps
      def check_sg(sg):
          
        # "E, G, H have sons K, M, N and one other"
        s = sg['E'] + sg['G'] + sg['H']
        if not (len(s) == 4 and 'K' in s and 'M' in s and 'N' in s): return False
      
        # "H, I have sons L, N and one other"
        s = sg['H'] + sg['I']
        if not (len(s) == 3 and 'L' in s and 'N' in s): return False
      
        # looks OK
        return True
      
      # collect viable maps
      sgs = list(sg for sg in make_map('EFGHI', 'JKLMNO') if check_sg(sg))
      
      # find the father of x in map d
      def father(x, d):
        return peek(k for (k, v) in d.items() if x in v)
      
      # choose the maps
      for (fs, sg) in product(ffs, sgs):
      
        # A, B, C, D have different numbers of grandsons
        s = list(sum(len(sg[s]) for s in fs[f]) for f in 'ABCD')
        if len(set(s)) != 4: continue
        # A has the most
        if s[0] != max(s): continue
      
        # grandfather of J and O
        gJ = father(father('J', sg), fs)
        gO = father(father('O', sg), fs)
        # they must be different people
        if gJ == gO: continue
      
        # output solution
        f = lambda s: join(s, sep="+")
        fmt = lambda m: map2str((k, f(v)) for (k, v) in m.items())
        printf("{gs} [grandfather(J) = {gJ}; grandfather(O) = {gO}]", gs=f(sorted([gJ, gO])))
        printf("  father -> sons: {fs}", fs=fmt(fs))
        printf("  son -> grandsons: {sg}", sg=fmt(sg))
        printf()
      

      Solution: One of the presenters is Adam, but the other can be any of: Brian, Colin, or David.

      The originally published solution is: “Adam and David”, but a later correction was made (with Teaser 2846) noting there are three valid solutions to the puzzle (given above).


      However, there is a unique solution if the end of the puzzle is changed to:

      The retirement gift was presented by the paternal grandfather of John and Oliver.

      Who was he?

      We can change the sense of the test at line 68 to ensure that the grandfathers of John and Oliver are the same person, and we find there are 2 possible family trees that lead to this situation, but in both cases the grandfather is Brian.

      Like

    • Hugh+Casement's avatar

      Hugh+Casement 8:34 am on 17 December 2021 Permalink | Reply

      Without trying Jim’s program, I think it’s like this:
      A’s son is H whose sons are L, N, and either K or M. D’s son is I who has no son.
      C’s son is G whose son is M or K (whichever is not H’s son).
      Brian has sons E (who has no sons) and F who is the father of J and O.

      Like

  • Unknown's avatar

    Jim Randell 10:22 am on 25 November 2021 Permalink | Reply
    Tags: , flawed   

    Teaser 2839: Unwholesome 

    From The Sunday Times, 19th February 2017 [link] [link]

    I have written down three positive numbers, the highest of which is an even two-figure number. Also, one of the numbers is the average of the other two. I have calculated the product of the three numbers and the answer is a prime number.

    You might be surprised that the product of three numbers is a prime but, of course, they are not all whole numbers — at least one of them is a fraction.

    What is the largest of the three numbers, and what is the product of the three?

    As presented there are 2 solutions to this puzzle.

    [teaser2839]

     
    • Jim Randell's avatar

      Jim Randell 10:23 am on 25 November 2021 Permalink | Reply

      The largest number is a 2-digit even integer, say 2n.

      And say the smallest number is the fraction p/q (where p and q are co-prime).

      The middle number is the arithmetic mean of these = (p + 2nq)/2q.

      The product is then: p (p + 2nq) n / q².

      And this is an integer. No non-trivial divisor of q can divide into p or (p + 2nq), so n must be divisible by q².

      Furthermore for the product to a prime, we must have: q² = n, and p = 1.

      Leaving the prime product as: (2q³ + 1).

      And the numbers as: a = 1/q; b = (2q³ + 1)/2q; c = 2q².

      We can solve this manually (remembering c is a 2 digit number):

      q=2: c = 8 [too small]
      q=3: c = 18; product = 55 [not prime]
      q=4: c = 32; product = 129 [not prime]
      q=5: c = 50; product = 251 [*** SOLUTION ***]
      q=6: c = 72; product = 433 [*** SOLUTION ***]
      q=7: c = 98; product = 687 [not prime]
      q=8: c = 128 [too big]

      or programmatically:

      Run: [ @replit ]

      from enigma import (irange, inf, is_prime, printf)
      
      for q in irange(2, inf):
        # check c is 2 digits
        c = 2 * q * q
        if c < 10: continue
        if c > 99: break
        # check product is prime
        m = 1 + c * q
        if not is_prime(m): continue
        # output solution
        printf("q={q}; a=1/{q} b={m}/{d} c={c}; product={m}", d=2 * q)
      

      Either way we find there are two solutions:

      Solution: (1) The largest number is 50, and the product of the three numbers is 251; or:
      (2) The largest number is 72, and the product of the three numbers is 433.

      The published solution is: “largest = 50; product = 251”. Apparently the setter was unaware of the second solution.

      Like

  • Unknown's avatar

    Jim Randell 8:57 am on 21 September 2021 Permalink | Reply
    Tags: , , flawed   

    Teaser 2823: Queuing 

    From The Sunday Times, 30th October 2016 [link] [link]

    Tickets for the event went on sale at 09:30. The queue started at 09:00 when 2 people arrived, then 4 more at 09:01, 6 more at 09:02 and so on until 60 more arrived at 09:29. Just 16 people arrived at 09:30, 16 more at 09:31, 16 more at 09:32 and so on. Tickets were sold steadily at a rate of 25 per minute (one per person).

    Joe and I were the first to arrive at our respective minutes, but we had identical waiting times before being sold our tickets, and no-one waited for less time to get a ticket. Joe was lucky to get the last ticket to be sold.

    At what time did Joe join the queue?

    This version of the text is provided by the setter, and differs from the version published in The Sunday Times.

    [teaser2823]

     
    • Jim Randell's avatar

      Jim Randell 8:58 am on 21 September 2021 Permalink | Reply

      The problem with this puzzle (particularly in the form it was published in the newspaper) was working out the intended mechanics of the situation.

      We suppose that all people joining the queue, do so simultaneously at the start of each specified minute. And that when the tickets are sold, they sold sequentially (a single ticket booth), with each sale taking exactly 1/25 minute (= 0.04m = 2.4s). This is apparently what the setter intended.

      The following Python program simulates the sale of tickets as described, and looks for minimal wait times that occur for the first member of a joining clump, until the value is repeated (then the earlier one is the setter, and the later one Joe, and Joe gets the last ticket, so sales end).

      It produces a log of events as it goes, and runs in 72ms.

      Run: [ @replit ]

      from enigma import irange, inf, sprintf, printf
      
      # format a time, (m=0, f=0) = 09:00.00
      def fmt(m, f=0):
        (h, m) = divmod(m, 60)
        return sprintf("{h:02d}:{m:02d}.{f:02d}", h=h + 9, f=4 * f)
      
      # the queue, record groups as (number of people, start minute)
      q = [(0, -1)]
      
      # extend the queue, add n people with value m
      def extend(q, n, m):
        if n > 0:
          q.append((n, m))
      
      # pop the queue, identifying the first in a group, return (x, flag)
      def pop(q):
        ((n, m), flag) = (q[0], 0)
        if n == 0:
          # move on to the next group
          q.pop(0)
          ((n, m), flag) = (q[0], 1)
        q[0] = (n - 1, m)
        return (m, flag)
      
      # size of the queue
      def size(q):
        return sum(n for (n, m) in q)
      
      # t = tickets sold
      # W = shortest waiting time
      # data = information for minimal wait times
      (t, W, data) = (0, inf, None)
      
      # run a timer
      for i in irange(0, inf):
        # m = minutes, f = fractions (1/25) of a minute
        (m, f) = divmod(i, 25)
      
        # on the minute
        if f == 0:
          # up to 09:29, 2m + 2 people join the queue
          # afterwards, 16 people join the queue
          n = (2 * m + 2 if m < 30 else 16)
          extend(q, n, m)
          printf("time {i}: added {n} people to queue, queue length = {q}", i=fmt(m, f), q=size(q))
      
        # from 9:30, one ticket is sold per frame
        if m > 29:
          t += 1
          # calculate waiting time (in frames)
          (x, flag) = pop(q)
          w = 25 * (m - x) + f
          printf("time {i}: joined at {x}, waited {w} frames, ticket {t}", i=fmt(m, f), x=fmt(x))
          # is this a new minimum?
          if not (w > W):
            printf("-> min wait = {w} frames for ticket {t}")
            if w < W:
              W = w
              data = list()
            # is this the first in their group?
            if flag:
              # record data
              data.append((x, m, f, t))
              # are we done?
              if len(data) == 2:
                printf("-> sold out after ticket {t}, queue length = {q}\n", q=size(q))
                # output solution
                for (n, (x, m, f, t)) in enumerate(data, start=1):
                  printf("{n} joined at {x}, served at {m}, ticket {t}", x=fmt(x), m=fmt(m, f))
                break
      

      Solution: Joe joined the queue at 10:06.

      The minimal wait time is 24.24 minutes (= 606/25 minutes).

      When the 1507 tickets sell out there are 399 people remaining in the queue.

      The setter joined the queue at 09:12, and got the 157th ticket at 09:36.24.

      Joe joined the queue at 10:06, and got the 1507th (and final) ticket at 10:30.24.

      So, if the tickets are numbered consecutively from 1, the digit sum of the two tickets is the same (and if they are numbered with leading zeros where necessary, the ticket numbers are anagrams of each other).

      Like

      • Jim Randell's avatar

        Jim Randell 9:03 am on 21 September 2021 Permalink | Reply

        The puzzle text as originally published in the newspaper read as follows:

        Tickets for the event went on sale at 09:30. The queue started at 09:00 when 2 people arrived, then 4 more at 09:01, 6 more at 09:02 and so on until 60 more arrived at 09:29. Just 16 people arrived at 09:30, 16 more at 09:31, 16 more at 09:32 and so on. Tickets were sold at 25 per minute (with one to each person in the queue) until they were sold out.

        Joe and I both had identical waiting times before being sold our tickets, despite me having arrived earlier, and no-one who got a ticket waited for less time than us.

        At what time did Joe join the queue?

        My interpretation of this was that people joined the queue simultaneously at the start of a minute. And when the tickets were sold, the 25 people at the head of the queue were processed simultaneously, at the start of each minute. (You can suppose there are 25 ticket booths, and each transaction takes exactly one minute). The wait times will always be whole numbers of minutes.

        The main problem I came across with this method was that we don’t know how many tickets there are (it is implied that they sell out at some point), but if we suppose Joe is in the last batch of 25 tickets sold we can solve the problem.

        Here is my code adapted to process the tickets 25 at a time.

        from enigma import (irange, inf, sprintf, printf)
        
        # format a time, m=0 = 09:00
        def fmt(m):
          (h, m) = divmod(m, 60)
          return sprintf("{h:02d}:{m:02d}", h=h + 9)
        
        # the queue, record groups as (number of people, start minute)
        q = [(0, -1)]
        
        # extend the queue, add n people with value m
        def extend(q, n, m):
          if n > 0:
            q.append((n, m))
        
        # pop the queue, identifying the first in a group, return (x, flag)
        def pop(q):
          ((n, m), flag) = (q[0], 0)
          if n == 0:
            # move on to the next group
            q.pop(0)
            ((n, m), flag) = (q[0], 1)
          q[0] = (n - 1, m)
          return (m, flag)
        
        # size of the queue
        def size(q):
          return sum(n for (n, m) in q)
        
        # t = tickets sold
        # W = shortest waiting time
        # data = information for minimal wait times
        (t, W, data) = (0, inf, None)
        
        # run a timer (in minutes)
        for m in irange(0, inf):
        
          # up to 9:29, 2m + 2 people join the queue
          # afterwards, 16 people join the queue
          n = (2 * m + 2 if m < 30 else 16)
          extend(q, n, m)
          printf("time {m}: added {n} people to queue, queue length = {q}", m=fmt(m), q=size(q))
        
          # from 9:30, 25 tickets are processed per minute
          if m > 29:
            for _ in irange(1, min(25, size(q))):
              t += 1
              # calculate waiting time (in frames)
              (x, flag) = pop(q)
              w = m - x 
              printf("time {m}: joined at {x}, waited {w} minutes, ticket {t}", m=fmt(m), x=fmt(x))
              # is this a new minimum?
              if not (w > W):
                printf("-> min wait = {w} minutes for ticket {t}{s}", s=(' [first]' if flag else ''))
                if w < W:
                  W = w
                  data = list()
                # is this the first in their group?
                if flag:
                  # record data
                  data.append((x, m, t))
        
            # are we done?
            if len(data) > 1:
              printf("\nsold out after {t} tickets, min wait = {w} minutes, queue length = {q}", q=size(q))
              # output solution
              for (n, (x, m, t)) in enumerate(data, start=1):
                printf("{n} joined at {x}, served at {m}, ticket {t}", x=fmt(x), m=fmt(m))
              printf()
              break
        

        We get the solution:

        minimal wait time = 24 minutes
        setter joined queue @ 9:08, served @ 9:32, ticket 73
        joe joined queue @ 9:09, served @ 9:33, ticket 91
        100 tickets sold, 894 people remaining in queue

        Like

  • Unknown's avatar

    Jim Randell 10:37 am on 7 September 2021 Permalink | Reply
    Tags: , flawed   

    Teaser 2820: Three ages 

    From The Sunday Times, 9th October 2016 [link] [link]

    Today is Alan’s, Brian’s and Colin’s birthday. If I write down their ages in a row in that order then I get a six-figure number. If I write down their ages in a row in the reverse order (i.e., Colin’s followed by Brian’s followed by Alan’s) then I get a lower six-figure number. When I divide the difference between these two six-figure numbers by the total of their three ages the answer is Alan’s age multiplied by Colin’s.

    What are Alan’s, Brian’s and Colin’s ages?

    As published there are 2 possible solutions to this puzzle.

    This puzzle was not included in the published collection of puzzles The Sunday Times Brainteasers Book 1 (2019).

    [teaser2820]

     
    • Jim Randell's avatar

      Jim Randell 10:38 am on 7 September 2021 Permalink | Reply

      If we assume the ages have 2 digits each (something not mentioned in the puzzle text), then we can quickly use the [[ SubstitutedExpression ]] solver from the enigma.py library to solve this problem.

      The following run file executes in 187ms.

      #! python3 -m enigma -rr
      
      # A = UV
      # B = WX
      # C = YZ
      
      SubstitutedExpression
      
      --distinct=""
      
      "(UV * YZ) * (UV + WX + YZ) + YZWXUV = UVWXYZ"
      

      And this finds two viable solutions.

      However it is not a great deal of work to write a program that considers ages that include 1-digit and 3-digit ages (with a suitable upper limit).

      The following Python program runs in 179ms, and finds the same two solutions.

      Run: [ @replit ]

      from enigma import (irange, printf)
      
      # permissible ages
      ages = irange(1, 120)
      
      for A in ages:
        for B in ages:
          AB = str(A) + str(B)
          if len(AB) > 5: break
          for C in ages:
            ABC = AB + str(C)
            if len(ABC) > 6: break
            if len(ABC) < 6: continue
            d = int(ABC) - int(str(C) + str(B) + str(A))
            if A * C * (A + B + C) == d:
              printf("A={A} B={B} C={C} [A:B:C={A}{B}{C} C:B:A={C}{B}{A}; d={d}]")
      

      Solution: The are two possible answers: Alan = 22, Brian = 61, Colin = 18; Alan = 99, Brian = 70, Colin = 33.

      These could be reduced to a single solution by adding one of the following conditions:

      (a) “None of the ages include the digit 0” → (22, 61, 18)
      (b) “Alan is older than Brian, who is older than Colin” → (99, 70, 33)

      The published solution is: “22, 61, 18 (or 99, 70, 33)”.

      We can run the Python program above to consider ages up to 9999, and we find that without constraining the values of A, B, C there are 5 possible solutions:

      (22, 61, 18)
      (37, 326, 3)
      (51, 830, 3)
      (78, 252, 6)
      (99, 70, 33)

      Like

    • GeoffR's avatar

      GeoffR 12:13 pm on 7 September 2021 Permalink | Reply

      # Using 2-digit ages: Alan = ab, Brian = cd, Colin = ef
      for ab in range(10, 100):
        for cd in range (10, 100):
          for ef in range(10, 100):
            abcdef = 10000*ab + 100*cd + ef  # ages in order
            efcdab = 10000*ef + 100*cd + ab  # ages in reverse order
            if abcdef < efcdab:continue
            diff = abcdef - efcdab
            if diff == (ab * ef) * (ab + cd + ef):
              print(f"Alan = {ab}, Brian = {cd}, Colin = {ef}")
              
      # Alan = 22, Brian = 61, Colin = 18
      # Alan = 99, Brian = 70, Colin = 33
      
      
      

      Like

      • Frits's avatar

        Frits 2:46 pm on 7 September 2021 Permalink | Reply

          
        # Using 2-digit ages: Alan = A, Brian = B, Colin = C
        # difference <d> does not depend on B
        for A in range(10, 100):
          sA = str(A)
          for C in range(10, A):
            # use dummy "10" for the value of B
            d = int(sA + "10" + str(C)) - int(str(C) + "10" + sA)
            (sumABC, r) = divmod(d, A * C)
            if r != 0: continue
            B = sumABC - A - C
            if not (9 < B < 100): continue
            print(f"Alan = {A}, Brian = {B}, Colin = {C}")
        

        Like

        • Jim Randell's avatar

          Jim Randell 4:11 pm on 7 September 2021 Permalink | Reply

          Or (still assuming 2-digit ages):

          from enigma import (irange, subsets, div, printf)
          
          # assuming 2 digit ages
          for (C, A) in subsets(irange(10, 99), size=2):
            B = div(9999 * (A - C), A * C)
            if B is None: continue
            B -= A + C
            if B < 10 or B > 99: continue
            printf("A={A} B={B} C={C}")
          

          or:

          #! python3 -m enigma -rr
          SubstitutedExpression
          
          --distinct=""
          
          "div(9999 * (UV - YZ), UV * YZ) - UV - YZ = WX"
          

          Like

      • Frits's avatar

        Frits 6:18 pm on 7 September 2021 Permalink | Reply

         
        # Using 2-digit ages: Alan = A, Brian = B, Colin = C
        #
        #  d = 9999 * (A - C) = (A * C) * (A + B + C)
        #    9999 = 3 * 3 * 11 * 101
        #
        # as A * C cannot be a multiple of 101 the sum A + B + C must be 101 or 202
        # this means that A * C must be a multiple of 99
        #            and (A * C) / (A - C) is 49.5 or 99
        
        for A in [x for x in range(11, 100) if x % 3 == 0 or x % 11 == 0]:
         for i, y in enumerate([A + 99, 2 * A + 99]):
            (C, r) = divmod(99 * A, y)
            if r > 0 or not (9 < C < 99): continue
            
            B = 101 - A - C if i == 0 else 202 - A - C
            if not (9 < B < 100): continue     # probably not needed
            
            print(f"Alan = {A}, Brian = {B}, Colin = {C}") 
        

        Like

      • Frits's avatar

        Frits 9:22 pm on 7 September 2021 Permalink | Reply

        Allowing for ages up to 999, again we don’t need to loop over B.

          
        # allow for high 3-digit ages
        for A in range(10, 1000):
          sA = str(A)
          
          if A < 100:
            # see previous posting
            rangeC = list(range(1, 10)) + \
                     [int((99 * A) / (A + 99)), int((99 * A) / (2 * A + 99))] 
          else:
            rangeC = range(1 , A  % 100)
          
          for C in rangeC:
            sC = str(C)
            if sC[0] > sA[0]: continue
            AC = sA + sC
            if len(sA + sC) > 5: break
            
            prodAC = A * C
            
            # allow Brian to be born on 9th October 2016
            minB = 10**(5 - len(AC)) if len(AC) != 5 else 0
            
            # how much does d decrement due to one increment of B? 
            if len(sA) > len(sC):
              difB = int((len(sA) - len(sC)) * "9" + "0")
            else:
              difB = 0
            
            # calculate difference for first B entry
            d = int(sA + str(minB) + sC) - int(sC + str(minB) + sA)  
            
            # rule: (A * C) * (A + minB + C) + n * (A * C) = d - n * difB 
            (n, r) = divmod(d - prodAC * (A + minB + C), prodAC + difB)
            
            if r > 0 or n < 0: 
              continue
            
            B = minB + n
            sB = str(B)
            
            ABC = sA + sB + sC
            if len(ABC) != 6: continue
            d = int(ABC) - int(sC + sB + sA)
            if prodAC * (A + B + C) == d:
              print(f"A={A} B={B} C={C} [A:B:C={A}{B}{C} C:B:A={C}{B}{A}; d={d}]")
        

        Like

        • Jim Randell's avatar

          Jim Randell 10:20 pm on 7 September 2021 Permalink | Reply

          Here’s my take on isolating B from the equation, by adjusting the definition of [[ ages() ]] you can allow whatever range of ages you want (including up to 9999).

          from itertools import product
          from enigma import (irange, div, printf)
          
          # decompose t into n numbers, min m
          def decompose(t, n, m=1, s=[]):
            if n == 1:
              if not (t < m):
                yield s + [t]
            else:
              for x in irange(m, t - n + 1):
                yield from decompose(t - x, n - 1, m, s + [x])
          
          # acceptable k digit ages
          def ages(k):
            if k == 3:
              return irange(100, 120)
            if k < 3:
              return irange(10**(k - 1), (10**k) - 1)
          
          # consider number of digits a, b, c; a + b + c = 6
          for (a, b, c) in decompose(6, 3):
            # age ranges
            (rA, rB, rC) = (ages(k) for k in (a, b, c))
            if not (rA and rB and rC): continue
            # multipliers
            mA = 10**(b + c) - 1
            mB = (10**c) - (10**a)
            mC = 10**(a + b) - 1
            # consider values for A and C
            for (A, C) in product(rA, rC):
              AC = A * C
              B = div(A * mA - C * mC - AC * (A + C), AC - mB)
              if B is not None and B in rB:
                printf("A={A} B={B} C={C}")
          

          Like

          • Frits's avatar

            Frits 10:53 pm on 7 September 2021 Permalink | Reply

            @Jim, very concise.

            Almost twice as fast with PyPy (for ages up to 999) although having 4 times as many (innermost) loops (187920 and 44649).

            Like

          • Frits's avatar

            Frits 12:16 pm on 8 September 2021 Permalink | Reply

            @Jim,

            While trying decompose(11, 3) I got into memory problems (5,6 GB memory used).

            Although itertools product is supposed to be a generator the problem disappeared when using separate loops for A and C (25 MB memory used).

            Like

            • Jim Randell's avatar

              Jim Randell 12:41 pm on 8 September 2021 Permalink | Reply

              I suspect internally [[ product() ]] is remembering all the values of the inner loops, because it doesn’t know that range objects are restartable iterators. Which will end up using a lot of memory if the ranges are large.

              So in the general case it would be better to use two for loops. (Which was how it was originally before I decided to save a line and a level of nesting).

              Like

          • Jim Randell's avatar

            Jim Randell 4:00 pm on 9 September 2021 Permalink | Reply

            Since I end up writing [[ decompose() ]] functions a lot in puzzles, I’ve added a helper function to enigma.py to generate them for you (see [[ Decompose() ]] and [[ decompose() ]]).

            For example, this program becomes:

            from enigma import (decompose, irange, div, printf)
            
            # acceptable <k> digit ages
            def ages(k):
              if k == 3:
                return irange(100, 120)
              if k < 3:
                return irange(10**(k - 1), (10**k) - 1)
            
            # consider number of digits (a, b, c), a + b + c = 6
            for (a, b, c) in decompose(6, 3, increasing=0, sep=0, min_v=1):
              # age ranges
              (rA, rB, rC) = (ages(k) for k in (a, b, c))
              if not (rA and rB and rC): continue
              # multipliers
              mA = 10**(b + c) - 1
              mB = (10**c) - (10**a)
              mC = 10**(a + b) - 1
              # consider values for A and C
              for A in rA:
                for C in rC:
                  AC = A * C
                  B = div(A * mA - C * mC - AC * (A + C), AC - mB)
                  if B is not None and B in rB:
                    printf("A={A} B={B} C={C}")
            

            Like

    • Frits's avatar

      Frits 5:52 pm on 9 September 2021 Permalink | Reply

      @Jim, Thanks, I will look into it.

      Calculating rC after A is known is faster:

        
      rC = range(10 ** (c - 1), (int(str(A)[0]) + 1) * 10 ** (c - 1))
      

      Like

    • Frits's avatar

      Frits 2:07 pm on 10 September 2021 Permalink | Reply

      Finding a galactic object for “Brian” 9.5 billion years old.
      This program runs in 8 seconds with PyPy.

       
      from enigma import decompose
      from math import ceil
      
      # acceptable k digit ages
      def ages(k):
        if k == 11:
          # universe is approx. 13.8 billion years old
          return range(10 ** (k - 1), 138 * 10 ** (k - 3))
        else:  
          return range(10 ** (k - 1), (10 ** k))
        
      L = 13  # number of digits concatenated A, B and C
      
      print("number of digits =", L)
      cnt = 0 
      cntsols = 0
      
      # consider number of digits a, b, c; a + b + c = L
      for (a, b, c) in decompose(L, 3, increasing=0, sep=0, min_v=1):
        # skip if A * C * (A + B + C) will have too many digits
        if 2 * a + c - 2 > L or 2 * c + a - 2 > L: 
          continue
        
        # group A range by first digit
        rA = [range(i * 10**(a - 1),  i * 10**(a - 1) + 10**(a - 1)) 
              for i in range(1, 10)]
        rB = ages(b)
        
        # multipliers
        mA = 10 ** (b + c) - 1
        mB = (10 ** c) - (10 ** a)
        mC = 10 ** (a + b) - 1
        
        # consider values for A and C
        for i, grp in enumerate(rA, 1):
          rC = range(10 ** (c - 1), (i + 1) * 10 ** (c - 1))
          
          # check first entry in C loop (see below)
          A = i * 10**(a - 1)  
          C = rC[0]
          if A * C == mB: 
            C = rC[1]     # next entry, we don't want to divide by zero
          
          numeratorB = A * mA - C * mC - A * C * (A + C)
          denominatorB = A * C - mB
          
          # numeratorB decreases and denominatorB increases as C becomes higher
          (B, r) = divmod(numeratorB, denominatorB)
          
          d1 = A * mA + B * mB - C * mC
          if d1 <= 0:    
            # we need a positive distance
            if numeratorB > 0: 
              # check when numeratorB becomes negative
              # (mC + A**2 + A * C) * C - A * mA = 0
              # quadratic equation: A * C**2 + (mC + A**2) * C - A * mA = 0
              newC1 = (-1 * (mC + A**2) + ((mC + A**2)**2 + 4 * A**2 * mA)**.5) 
              newC1 /= (2 * A)
              newC2 = mB / A      # when will denominatorB become positive again?
              newCs = sorted([newC1, newC2])
              low = ceil(newCs[0])
              hgh = int(newCs[1])
              rC = range(low, hgh + 1)
         
          for A in grp:
            for C in rC:
              cnt += 1
              AC = A * C
              
              # difference rule: A * mA + B * mB - C * mC = A * C * (A + B + C)
              if AC == mB: continue  # don't divide by zero
              
              (B, r) = divmod(A * mA - C * mC - AC * (A + C), AC - mB)
              
              if B < 0: break  
              
              if r == 0 and B in rB:
                d1 = int(str(A) + str(B) + str(C)) - int(str(C) + str(B) + str(A))
                d2 = AC * (A + B + C)
                
                print(f"A={A} B={B} C={C}, AC={AC} diff1={d1} diff2={d2}")
                cntsols += 1
            
      print("number of solutions", cntsols, "loop count =", cnt) 
      

      Like

    • GeoffR's avatar

      GeoffR 1:49 pm on 12 September 2021 Permalink | Reply

      
      ' A Solution in Visual Basic 2019
      Module Module1
        Public Sub Main()
          Dim A, B, C As Integer ' for Alan, Brian and Colin
          Dim AGES, Rev_AGES, DIFF_AGES As Integer
          For A = 10 To 99
            For B = 10 To 99
              If B = A Then
                Continue For
              End If
              For C = 10 To 99
                If C = B Or C = A Then
                  Continue For
                End If
                AGES = 10000 * A + 100 * B + C
                Rev_AGES = 10000 * C + 100 * B + A
                If AGES > Rev_AGES Then
                  DIFF_AGES = AGES - Rev_AGES
                  If DIFF_AGES = (A + B + C) * (A * C) Then
                    Console.WriteLine("Alan = {0}, Brian = {1}, Colin = {2}", A, B, C)
                  End If
                End If
              Next   'C
            Next   'B
          Next   'A
          Console.ReadKey()   'Freeze console screen
        End Sub
      End Module
      
      'Alan = 22, Brian = 61, Colin = 18
      'Alan = 99, Brian = 70, Colin = 33
      
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 4:31 pm on 13 June 2021 Permalink | Reply
    Tags: , flawed   

    Brain-Teaser 35: After-lunch golf 

    From The Sunday Times, 19th November 1961 [link]

    Gee and Jay play — for £1 the match, 5s. a hole, and 1s. a stroke — a golf match of nine holes which is decided on the ninth green. Neither takes less than four or more than nine strokes at any hole and the
    results vary for every hole.

    Gee wins five holes and the match, and takes 22s. off his opponent, but had the result at the last hole been reversed he would have lost 10s.

    At the eighth hole all the strokes travel an exact number of yards straight towards the pin, but whilst each of Gee’s travels one half the distance of his previous stroke, each of Jay’s goes one quarter the distance of its predecessor.

    (i) In how many strokes did Gee complete the round?
    (ii) What is the length of the eighth hole?

    [teaser35]

     
    • Jim Randell's avatar

      Jim Randell 4:31 pm on 13 June 2021 Permalink | Reply

      I struggled to find a unique solution for this puzzle, and had to make several assumptions along the way. Maybe I just don’t know enough about golf.

      Let’s start by looking at the 8th hole:

      If G makes n strokes, and the distance of the final one is x, then the total distance is:

      x + 2x + 4x + … + (2^n)x = (2^n − 1)x

      And if J makes m strokes, and the distance of the final one is y, then the total distance is:

      y + 4y + 16y + … + (4^m)y = (4^m − 1)y / 3

      So the overall distance of the hole must be some multiple of: lcm(2^n − 1, (4^m − 1) / 3)

      The following values work (for holes with a distance of less than 1000 yards):

      n=4 m=4: dist = 255k; Gs=(136, 68, 34, 17)k, Js=(192, 48, 12, 3)k
      n=5 m=5; dist = 341k; Gs=(176, 88, 44, 22, 11)k, Js=(256, 64, 16, 4, 1)k
      n=8 m=4; dist = 255k; Gs=(128, 64, 32, 16, 8, 4, 2, 1)k, Js=(192, 48, 12, 3)k

      If we limit the length of a hole we can reduce the possibilities, but even the smallest possible distance (255 yards) has 2 options for the score.

      As far as the actual match goes I’m assuming the winner of the match is the player who won the greatest number of individual holes, and the loser pays the winner £1 (= 20s), and for each individual hole the loser of each hole pays the winner 5s, plus 1s per stroke for the difference in strokes.

      I further assumed that “the results vary for each hole” mean that no score for any hole is repeated.

      We know that G wins 5 holes (including the final hole), and hole 8 is either drawn, or G loses it by 4 strokes.

      If the 8th hole is drawn there are 2 possibilities (scores from G’s perspective):

      8th hole = 4-4; Gs wins = 4-5, 5-6, 6-7, 7-8, 8-9; other holes = 8-4, 9-5, 9-4
      8th hole = 5-5; Gs wins = 4-5, 5-6, 6-7, 7-8, 8-9; other holes = 8-4, 9-5, 9-4

      The first gives G a total of 60 strokes, and J a total of 52.

      G wins 20 + (5 − 3)×5 + (52 − 60) = 22 shillings.

      And if the result of one of G’s wins (on the last hole) was reversed, there would be no winner on holes (each won 4, and 1 was drawn), so the match is drawn, and only money for the number of strokes changes hands. G has a total of 61 strokes, and J a total of 51 strokes, so G loses 10s. (Although I think J could argue that in this case he won the match).

      The second gives G a total of 61 strokes, and J a total of 53.

      Again, if the result of one of G’s wins is reversed, G’s total goes down by 1 stroke and J’s goes up by 1, so G loses 10s.

      So, if we limit the maximum possible distance of a hole to 340 yards, then only the first of these options remains, and gives the solution:

      Solution: (i) Gee completed the round in 60 strokes. (ii) The 8th hole was 255 yards long.

      Which is the published solution.

      Like

      • Jim Randell's avatar

        Jim Randell 10:35 am on 15 June 2021 Permalink | Reply

        Here is a Python program that solves the puzzles according to the assumptions described in my previous comment.

        It runs in 86ms.

        Run: [ @replit ]

        from enigma import irange, subsets, update, lcm, group, unpack, multiset, join, printf
        
        # possible strokes per hole
        strokes = irange(4, 9)
        
        # consider the number of strokes on the 8th hole (G=x, J=y)
        def hole8():
          for (x, y) in subsets(strokes, size=2, select="M"):
            # calculate minimal distance
            tx = sum(pow(2, n) for n in irange(0, x - 1))
            ty = sum(pow(4, n) for n in irange(0, y - 1))
            d = lcm(tx, ty)
            if d < 1000:
              printf("[hole8: G={x} J={y}; dist = {d}k; Gs={Gs}k Js={Js}k]",
                Gs=tuple(pow(2, n) * d // tx for n in irange(0, x - 1))[::-1],
                Js=tuple(pow(4, n) * d // ty for n in irange(0, y - 1))[::-1],
              )
              yield (x, y)
        # collect hole 8 scores by score
        score = unpack(lambda x, y: y - x)
        h8s = group(hole8(), by=score)
        
        # collect possible wins/losses
        scores = group(subsets(strokes, size=2, select="M"), by=score)
        
        # calculate the gain for a sequence of holes
        def gain(hs):
          # total gain (shillings), difference (in holes)
          T = d = 0
          for x in hs:
            if x < 0:
              # G wins the hole
              T += 5 - x
              d += 1
            elif x > 0:
              # G loses the hole
              T -= 5 + x
              d -= 1
          if d > 0:
            # G wins the match (on holes, not strokes)
            T += 20
          elif d < 0:
            # G loses the match
            T -= 20
          return T
        
        # find scores with stroke differences in ds
        def complete(ds, ss):
          if not ds:
            if len(set(ss)) == len(ss):
              yield ss
          else:
            (k, v) = ds[0]
            for xs in subsets(scores[k], size=v, fn=list):
              yield from complete(ds[1:], ss + xs)
        
        # output holes and total strokes
        def output(hs, ss):
          holes = list()
          G = J = 0
          for (h, (x, y)) in zip(hs, ss):
            if h > 0: (x, y) = (y, x)
            holes.append((x, y))
            G += x
            J += y
          printf("{holes} -> G={G} J={J}", holes=join((f"{x}-{y}" for (x, y) in holes), sep=", ", enc="()"))
        
        # G wins 5 holes (including the final one)
        for Gw in subsets([-1, -2, -3, -4, -5], size=5, select="R"):
          # G does not win any of the other 4 holes
          for Gl in subsets([0, 1, 2, 3, 4, 5], size=4, select="R"):
            # calculate G's winnings
            hs = list(Gw + Gl)
            # hole 8 is 0 or -4
            if not any(k in hs for k in h8s.keys()): continue
            w = gain(hs)
            if w != 22: continue
        
            # look for a 9th hole, which if swapped would give -10s
            for x in set(Gw):
              hs_ = update(hs, [hs.index(x)], [-x])
              w_ = gain(hs_)
              if w_ != -10: continue
        
              # count the scores, and reject any collection that would require a duplicate score
              s = multiset.from_seq((abs(x) for x in hs))
              if any(s.count(k) > len(scores[k]) for k in s.keys()): continue
        
              # choose a hole 8
              for (i, h8) in enumerate(hs):
                for s8 in h8s.get(h8, []):
                  # count the remaining scores
                  for ss in complete(list(s.difference([abs(h8)]).items()), [s8]):
                    # output solution (hole 8 first)
                    output([h8] + hs[:i] + hs[i + 1:], ss)
        

        The distance for the 8th hole is limited to below 1000 yards, so the program produces two possible answers.

        In the output the holes are not listed in play order, rather hole 8 comes first, then the remaining holes, starting with those that G won.

        Like

      • Jim Randell's avatar

        Jim Randell 5:49 pm on 19 June 2021 Permalink | Reply

        With Teaser 36 the following was published:

        In Brain-Teaser No. 35 (Sunday, November 19) owing to the omission of the result of the eighth hole (halved in four) several alternative solutions became possible. No reader who submitted any of these was excluded from the prize.

        Which I think means we are take it that the result of the eighth hole was a draw, each player taking 4 strokes.

        With this additional information we can reduce the number of possible solutions (although we still need to limit the distance of the eighth hole, or the individual strokes, to deduce a unique distance).

        Like

    • Jim Olson's avatar

      Jim Olson 9:14 pm on 13 June 2021 Permalink | Reply

      I’m not following the total score for each. If Gee wins the match then he has the lowest total strokes. In the analysis presented Jay should have won the match. It is not determined by the number of holes won. I understand the assumption you made but that is not golf rules.

      Like

      • Jim Randell's avatar

        Jim Randell 11:02 pm on 13 June 2021 Permalink | Reply

        I tried various things to try and get a unique solution, and this was the only way I found. Looking on Wikipedia [link] it seemed to be allowed (“match play” vs “stroke play” – I did start off using the latter, but didn’t get anywhere).

        I don’t think a modern Teaser puzzle would be published that didn’t have at least a brief description of the scoring system that is to be used. But this one is from 60 years ago.

        Like

    • Jim Olson's avatar

      Jim Olson 2:18 am on 14 June 2021 Permalink | Reply

      I agree your interpretation is what the setter had in mind. However, after many years of playing golf In tournaments and at golf clubs the tournament or match was won by the golfer with the lowest number of total strokes. The setter should have made it clear how the scoring for the match winner was to be computed. It would have saved quite a bit of time.

      Like

  • Unknown's avatar

    Jim Randell 7:34 am on 2 May 2021 Permalink | Reply
    Tags: by: C. R. J. Fleming, flawed   

    Brain-Teaser 32: [Square farm] 

    From The Sunday Times, 29th October 1961 [link]

    A, B, & C are sitting in a railway carriage, and A, an Australian, is talking to B about his farm in Australia.

    “It is square”, he says, and tells B the length of its sides: a whole number of miles; “but I am thinking of selling a rectangular part of it whose sides are in length a whole plural number of miles”. He tells B the area of the rectangle: an odd number of square miles.

    B says: “If I knew whether its breadth was less than two-thirds of its length, I could tell you its dimensions”. A tells him that its breadth is more than two-thirds of its length.

    C, a stranger, who had been listening to this conversation, but missed the area of the rectangle, nevertheless correctly deduced its dimensions, although, he reflected, had A‘s farm had sides one mile longer he could not have done so.

    What are the lengths of the sides of  A‘s farm, and of the rectangular part to be sold?

    This puzzle was originally published with no title.

    [teaser32]

     
    • Jim Randell's avatar

      Jim Randell 7:34 am on 2 May 2021 Permalink | Reply

      I think this puzzle is flawed.

      B knows the size of A’s farm (which gives the maximum dimension of the rectangle – assuming the rectangle is aligned with the square), and also the area of the rectangle (which were are told is odd).

      And he must be able to narrow down the options (= non-trivial divisor pairs of the odd area, subject to the maximum dimension) to two possible values, which can then be distinguished by knowing if the breadth of the rectangle is less than 2/3 the length.

      So, for instance an area of 63 has two options:

      63 = 3 × 21 = 7 × 9

      So, if the size of the farm is at least 21 × 21, and B is told an area of 63, this is a candidate solution. (Or 17 × 17 if the rectangle does not have to be aligned with the square).

      If the rectangle is allowed to be a square the next candidate solution is when the size of the farm is at least 25 × 25, and B is told an area of 225:

      225 = 9 × 25 = 15 × 15.

      At 27 × 27, an area of 81 becomes viable:

      81 = 9 × 9 = 3 × 27

      When we get to 33 × 33 we get two further possible solutions:

      99 = 3 × 33 = 9 × 11
      165 = 5 × 33 = 11 × 15

      And so on.

      C knows the size of the farm, but did not hear the area of the rectangle, and so presumably also doesn’t know that the area is odd.

      But even for the minimum possible area of 21 × 21 there are 16 possible areas that have 2 decompositions into viable rectangles, and C has no way to choose between them.

      So let’s suppose that C does know that the area of the rectangle is odd. (Maybe B commented: “Ah, so the area of the rectangle is odd”, and C heard this, but not the actual value of the area).

      For a farm of size 21 × 21 to 24 × 24 there is only one possible area (= 63), and as we know the breadth of the rectangle is more than 2/3 the length, this means it must be 7 × 9. So if C had heard any of these farm areas, they could deduce the area of the rectangle.

      But when we get to 25 × 25 the possibility of a rectangle of area 225 appears (giving a rectangle of 15 × 15, where the breadth is more than 2/3 the length), so C cannot determine which rectangle it is.

      So the solution would seem to be:

      Solution: A’s farm is 24 × 24 miles. The rectangular area is 7 × 9 miles.

      However the published solution is that A’s farm is 25 × 25 miles.

      I suppose the perimeter of the square could be required to be unaffected, but that is not mentioned in the puzzle text. (And if the rectangle doesn’t have to be aligned with the sides of the square we can easily fit a 9×25 rectangle entirely within a 25×25 square, but not within a 24×24 square, which makes 24×24 a more likely answer).


      This Python program runs in 52ms.

      Run: [ @replit ]

      from enigma import (irange, inf, subsets, group, multiply, filter2, unpack, printf)
      
      # solve for an n mile x n mile area
      def solve(n):
        # group potential sub-rectangles by area
        d = group(subsets(irange(2, n), size=2, select="R"), by=multiply)
      
        for k in sorted(d.keys()):
          # k must be odd
          if k % 2 != 1: continue
          vs = d[k]
          # there must be 2 choices for the area
          if len(vs) != 2: continue
          # that are distinquished by known in a < (2/3) b
          (lt, ge) = filter2(unpack(lambda a, b: 3 * a < 2 * b), vs)
          if not (len(lt) == 1 and len(ge) == 1): continue
          printf("[n={n}] {k} -> {vs} -> {lt} + {ge}")
          yield (k, lt[0], ge[0])
      
      ps = list()
      for n in irange(1, inf):
        rs = list(solve(n))
        if len(rs) > 1:
          printf("farm = {n1} x {n1}", n1=n - 1)
          if len(ps) == 1:
            (k, _, (a, b)) = ps[0]
            printf("rectangle = {a} x {b} [area = {k}]")
          break
        ps = rs
      

      Like

  • Unknown's avatar

    Jim Randell 8:14 am on 16 March 2021 Permalink | Reply
    Tags: , flawed   

    Teaser 2529: [Cost estimates] 

    From The Sunday Times, 13th March 2011 [link] [link]

    A letter to The Times concerning the inflated costs of projects read:

    When I was a financial controller, I found that multiplying original cost estimates by 𝛑 used to give an excellent indication of the final outcome.

    Interestingly, I used the same process (using 22/7 as a good approximation for 𝛑). On one occasion, the original estimate was a whole number of pounds (less than £100,000), and this method for the probable final outcome gave a number of pounds consisting of exactly the same digits, but in the reverse order.

    What was the original estimate?

    When originally published the amount was given as “less than £10,000”, which was raised to “less than £100,000” in the following issue. But even with this change the puzzle is still open to interpretation.

    This puzzle was originally published with no title.

    [teaser2529]

     
    • Jim Randell's avatar

      Jim Randell 8:15 am on 16 March 2021 Permalink | Reply

      What the puzzle isn’t clear on is what happens to any fractional part of the new estimate. (Which there would always be if you were to multiply by 𝛑).

      If we round down (simply ignoring any fractional part) in the result, then we can get a solution to the original puzzle:

      £185 × 22/7 = £581.43 → £581

      And we also get the same result if we round to the nearest pound.

      And a different unique solution if we round up:

      £29 × 22/7 = £91.14 → £92

      Raising the limit to £100,000 then we get the following additional solutions:

      £22407 × 22/7 = £70422

      Rounding to nearest:

      £30769 × 22/7 = £96702.57 → £96703

      Which we also get if we round up, along with:

      £29429 × 22/7 = £92491.14 → £92492

      So the only way we can get a unique solution with the revised upper limit is to assume that, before rounding, the new estimate was a whole number of pounds, and so no rounding was necessary. In this case only the pair £22407 → £70422 remain as a candidate solution, and this was the required answer.

      This makes a manual solution easier (and a programmed solution a little faster), as we know the original estimate must be a multiple of 7.

      The following Python program lets you play with various rounding methods.

      from enigma import (irange, divf, divc, divr, div, nreverse, printf)
      
      # the new estimate is the original estimate multiplied by 22/7
      # choose an appropriate function from the following
      # - fn=divf: rounded down
      # - fn=divc: rounded up
      # - fn=divr: rounded to nearest integer
      # - fn=div: exact division
      estimate = lambda x, fn=div: fn(x * 22, 7)
      
      # consider the original estimate x
      for x in irange(1, 99999):
        # multiply by 22/7 for new estimate n
        n = estimate(x)
        if n is None or n % 10 == 0: continue
        # new estimate is reverse of the original
        if nreverse(n) == x:
          printf("original {x} -> {n}")
      

      Solution: The original estimate was: £22,407.


      If the estimates had been constrained to be between £100,000 and £1,000,000 then there is a single solution whichever rounding method is chosen:

      £246,477 × 22/7 = £774,642

      Like

    • Frits's avatar

      Frits 1:04 pm on 17 March 2021 Permalink | Reply

      # consider original cost abcde w    
      # 22 * abcde = 7 * edcba 
      
      # 0 < a < 4 as a * 22 / 7 < 10
      # a must be also be even as 22 * abcde is even
      # so a = 2 and 5 < e < 10
      # 22 * 2bcde = 7 * edcb2 --> e is 7 or 2 --> e is 7 
      
      # equation 22 * 2bcd7 = 7 * 7dcb2
      
      # cost 2-digit number: 
      # -- 27 is not divisible by 7
      # cost 3-digit number: 4914 <= 22 * 2b7 <= 5544 so 2 < b < 5 
      # -- no 2b7 is divisible by 7 for 2 < b < 5 
      # cost 4-digit number: 49014 <= 22 * 2bc7 <= 55944 so 1 < b < 6 
      # cost 5-digit number: 490014 <= 22 * 2bcd7 <= 559944 so 1 < b < 6 
      
      # ...d7 * 22 ends on 54 + d * 20 --> ends on o4 where o is an odd digit
      # b = 2 --> ...22 * 7 = ...54, 54 + d * 20 ends on 54 so d = 0 or 5
      # b = 3 --> ...32 * 7 = ...24, wrong
      # b = 4 --> ...42 * 7 = ...94, 54 + d * 20 ends on 94 so d = 2 or 7
      # b = 5 --> ...52 * 7 = ...64, wrong
      
      # b = 2 --> d = 0 or 5,
      # b = 4 --> d = 2 or 7
      
      # 4-digit numbers 2207, 2257, 2427 and 2477 are not not divisible by 7
      
      # divisibility by 11 requires that the difference between 
      # the sum of the the digits in odd positions and 
      # the sum of all the digits in even positions is 0 or divisible by 11
      
      # 22x07, sum even positions = 2  --> (9 + x - 2) % 11 = 0 -- > x = 4
      # 22407 is divisible by 7
      
      # 22x57, sum even positions = 7  --> (9 + x - 7) % 11 = 0 -- > x = 9
      # 22957 is not divisible by 7
      
      # 24x27, sum even positions = 6  --> (9 + x - 6) % 11 = 0 -- > x = 8
      # 24827 is not divisible by 7
      
      # 24x77, sum even positions = 11 --> (9 + x - 11) % 11 = 0 -- > x = 2
      # 24277 is not divisible by 7
           
      # so 22407 * 22/7 = 70422  
      

      Like

    • John Crabtree's avatar

      John Crabtree 1:40 pm on 18 March 2021 Permalink | Reply

      X = abcde, Y = edcba where X * 22 = Y * 7
      and so 2e = 7a mod 10, and so a = 2 and e = 7

      By digital roots, the sum of the digits in X = 0 mod 3. X = Y = 0 mod 3
      X = 0 mod 7. Y = 0 mod 11, and so X = 0 mod 11
      And so X = 231*M, Y = 726*M, and M = 7 mod 10
      Or X = 1617 + 2310*N and Y = 5082 + 7260*N

      By inspection X cannot have 2, 3 or 4 digits
      70,000 < Y < 80,000 and so N = 9 or 10, which is invalid by inspection.
      N = 9 gives X = 22407 and Y = 70422, which is valid.

      If X 6 digits, there are only 14 possible values of N, ie 96 to 109, to check.

      Like

      • Frits's avatar

        Frits 12:12 pm on 19 March 2021 Permalink | Reply

        @John,

        Maybe you used the congruent sign in your analysis and it was replaced by equal signs.
        If so you might try the enclosure of text as mentioned in Teaser 2756.
        If not the analysis is wrong as 0 mod 11 equals 0.

        Please elaborate as I am not an expert in modular arithmetic (I gather X must be a multiple of 3, 7 and 11?).

        Like

        • John Crabtree's avatar

          John Crabtree 4:16 pm on 19 March 2021 Permalink | Reply

          @Frits
          I do not recall the congruence sign from when I was first introduced to modulo arithmetic nearly 50 years ago. I have always used the equals sign (perhaps incorrectly) followed by mod n.
          X = 0 mod 3 means that X is divisible by 3. And so, yes, X is divisible by 3, 7 and 11. As it also ends in 7 the solution space becomes very small. HTH

          Like

    • Hugh Casement's avatar

      Hugh Casement 12:25 pm on 19 March 2021 Permalink | Reply

      I meant to post this on St Patrick’s day, before most of the other comments appeared.

      I’m sure that an integer solution is intended, so no rounding is necessary.
      The original estimate must therefore be an integer multiple of 7.
      The result is even, so the original estimate (with its digits in reverse order) must start with 2: any larger value would yield a result with more digits.
      The result is a multiple of 11, so the original estimate (using the same digits) must be too.
      Admittedly, that still means a lot of trial & error if we don’t use a computer.

      22/7 is a lousy approximation to pi! Much better is 355/113, but I think that can work only if the original estimate is allowed to have a leading zero.

      Like

  • Unknown's avatar

    Jim Randell 8:42 am on 23 February 2021 Permalink | Reply
    Tags: , flawed   

    Teaser 2777: Summing up 2015 

    From The Sunday Times, 13th December 2015 [link] [link]

    I asked Harry and Tom to write down three numbers that between them used nine different digits and which added to 2015. They each succeeded and one of Harry’s three numbers was the same as one of Tom’s. I noticed that Harry’s three numbers included a perfect square and Tom’s included a higher perfect square.

    What were those two squares?

    [teaser2777]

     
    • Jim Randell's avatar

      Jim Randell 8:44 am on 23 February 2021 Permalink | Reply

      As stated there are multiple solutions to the puzzle.

      Having tackled similar problems before it seems likely that the intention of the setter is:

      “… three numbers that between them used nine different digits, each of them [exactly] once …”

      or possibly:

      “… three 3-digit numbers that between them used nine different digits …”

      Any solution for the latter will appear as a solution for the former, so we will use the first one to solve the puzzle (as it turns out it does give a unique answer).

      The following Python code generates possible sums that use a square and 2 other numbers to produce the required total, and where each of 9 digits is used exactly once in the summands.

      It then choose sums that use different squares, but have one of the other numbers in common.

      It runs in 95ms.

      Run: [ @repl.it ]

      from enigma import (
        cproduct, powers, inf, is_duplicate, irange, concat, multiset,
        group, unpack, subsets, intersect, join, arg, printf
      )
      
      # target sum
      Y = arg(2015, 0, int)
      printf("[Y={Y}]")
      
      # generate (s, a, b) sums, s is square, s + a + b = Y
      def generate(Y):
        # consider squares
        for s in powers(0, inf, 2):
          if s > Y: break
          if is_duplicate(s): continue
      
          # find sums: s + a + b = Y
          t = Y - s
          for a in irange(0, t // 2):
            b = t - a
            # check for sums with 9 different digits
            ds = concat(s, a, b)
            # check for 9 different digits
            if len(ds) == 9 and len(set(ds)) == 9:
              yield (s, a, b)
      
      # group sums by the square
      d = group(generate(Y), by=unpack(lambda s, a, b: s))
      
      # collect the squares involved
      r = multiset()
      
      # consider squares for Harry and Tom
      for (sH, sT) in subsets(sorted(d.keys()), size=2):
      
        # choose decompositions
        for (dH, dT) in cproduct([d[sH], d[sT]]):
      
          # that share a number
          if intersect([dH, dT]):
            printf("[H = {dH}; T = {dT}]", dH=join(dH, sep=" + "), dT=join(dT, sep=" + "))
            r.add((sH, sT))
      
      # output solutions
      for (k, v) in r.most_common():
        printf("squares = {k} [{v} solutions]", k=join(k, sep=", "))
      

      Solution: Harry’s square was 324. Tom’s square was 784.

      There are two ways to arrive at the solution:

      Harry: 324 + 785 + 906 = 2015
      Tom: 784 + 325 + 906 = 2015

      Harry: 324 + 786 + 905 = 2015
      Tom: 784 + 326 + 905 = 2015

      The summands in each sum use all the digits exactly once except for the digit 1.

      To see the multiple solutions without the restriction that each of the 9 digits is used exactly once, you can remove line 15 and the [[ len(ds) == 9 ]] clause from line 24.


      The same puzzle could have been set in 2019, and had the same answer.

      If the puzzle were set in 2022, there would only be one way to arrive at the (different) answer.

      Like

    • Frits's avatar

      Frits 2:04 pm on 23 February 2021 Permalink | Reply

      I assumed Harry’s and Tom’s squares were not the number they shared (ABCD).

      from enigma import SubstitutedExpression, is_square
      
      # the alphametic puzzle
      p = SubstitutedExpression(
        [
        # Use 4-digit numbers as sum is limited to 2015
        
        # to reduce the output assume EFGH (Harry) and MNOP (Tom) 
        # are both perfect squares
        "is_square(EFGH)",
       
        # use a variable as right hand side to reduce the number of loops
        "2015 - ABCD - EFGH = IJKL",
        
        # nine different digits
        "len(str(ABCD) + str(EFGH) + str(IJKL)) == \
         len(set(str(ABCD) + str(EFGH) + str(IJKL))) == 9",
        
        # Tom's included a higher perfect square
        "MNOP > EFGH and is_square(MNOP)",
       
        # use a variable as right hand side to reduce the number of loops
        "2015 - ABCD - MNOP = QRST",
        
        # nine different digits
        "len(str(ABCD) + str(MNOP) + str(QRST)) == \
         len(set(str(ABCD) + str(MNOP) + str(QRST))) == 9",
        ],
        answer="EFGH, MNOP",
        d2i=dict([(k, "AEIMQ") for k in range(3, 10)]),
        verbose=0,
        distinct="",
      )
      
      # Print answers
      sols = set(sol for (_, sol) in p.solve())
      print(f"answer = {sols}")
      

      Like

  • Unknown's avatar

    Jim Randell 8:16 am on 26 January 2021 Permalink | Reply
    Tags: , flawed   

    Teaser 2772: Madam I’m Adam 

    From The Sunday Times, 8th November 2015 [link] [link]

    Adam noticed that today’s Teaser number was a four-figure palindrome. He told me that he had written down [a] four-figure palindrome and he asked me to guess what it was. I asked for some clues regarding its prime factors and so he told me, in turn, whether his number was divisible by 2, 3, 5, 7, 11, 13, … Only after he had told me whether it was divisible by 13 was it possible to work out his number.

    What was his number?

    When this was originally published “another” was used where I have placed “[a]”, but this makes the puzzle unsolvable. However, as presented above, there is a unique solution.

    [teaser2772]

     
    • Jim Randell's avatar

      Jim Randell 8:17 am on 26 January 2021 Permalink | Reply

      The use of “another” in the puzzle text implies that the palindrome 2772 is excluded from the set of possibilities, but if this is the case the puzzle is not solvable. So instead we just consider that Adam has told the setter that he has written down some 4-digit palindrome (which may be 2772), and the setter has to guess it.

      This Python program considers increasing prime numbers p, and looks for palindromes that can be uniquely identified by knowing if it is divisible by primes up to (and including) p.

      To solve this puzzle we look up to p = 13, but the maximum prime can be specified on the command line. (We have to go to 859 to be sure of determining the palindrome).

      The program runs in 45ms.

      Run: [ @repl.it ]

      from enigma import Primes, irange, filter_unique, diff, join, arg, printf
      
      # max prime
      N = arg(13, 0, int)
      
      # 4-digit palindromes
      palindromes = sorted(1001 * a + 110 * b for a in irange(1, 9) for b in irange(0, 9))
      #palindromes.remove(2772) # puzzle text says 2772 is excluded, but that makes it impossible
      
      # palindromes unique by divisibility of primes, but not unique by shorter sequences
      r = set()
      # consider sequences of primes by increasing length
      ps = list()
      for p in Primes(N + 1):
        ps.append(p)
        # find unique palindromes by this sequence of primes
        s = filter_unique(palindromes, lambda x: tuple(x % p == 0 for p in ps)).unique
        # unique palindromes we haven't seen before
        s = diff(s, r)
        if s:
          printf("{p} -> {s}", s=join(s, sep=", ", enc="()"))
        # update the list of unique palindromes
        r.update(s)
      

      Solution: The number was 6006.


      If 2772 is removed from the set of possible palindromes (by removing the comment from line 8), we see that 8778 would also be uniquely identified by the divisibility values for primes up to 13.

      So although the setter would know the answer (because he knows if the number is divisible by 13 or not), we can’t work it out:

      6006 → 2=Y, 3=Y, 5=N, 7=Y, 11=Y, 13=Y
      8778 → 2=Y, 3=Y, 5=N, 7=Y, 11=Y, 13=N, [17=N, 19=Y]
      2772 → 2=Y, 3=Y, 5=N, 7=Y, 11=Y, 13=N, [17=N, 19=N]

      But, if 2772 is included in the set of possible palindromes, then 8778 and 2772 cannot be distinguished until we are told the answer for divisibility by 19, so the fact that the setter can work out the number at p = 13 means that it must be 6006.

      There are two palindromes that can be distinguished with a shorter sequence of answers:

      5005 → 2=N, 3=N, 5=Y, 7=Y
      5775 → 2=N, 3=Y, 5=Y, 7=Y

      Note that all palindromes are divisible by 11.

      Like

    • Frits's avatar

      Frits 8:08 pm on 26 January 2021 Permalink | Reply

      With fewer modulo calculations.

      from collections import Counter
       
      # max prime
      N = 13
      
      # list of prime numbers
      P = [2, 3, 5, 7, 11, 13]
       
      # 4-digit palindromes
      palindromes = sorted(1001 * a + 110 * b for a in range(1, 10) 
                                              for b in range(0, 10))
      
      # initialize dictionary (divisibility by prime)                                    
      d = {key: [] for key in palindromes}
       
      singles = []
      # consider sequences of primes by increasing length
      for p in P:
        # maintain dictionary (divisibility by prime)   
        for x in palindromes:
          d[x].append(x % p == 0)
         
        c = Counter(map(tuple, d.values()))
        # get combinations unique by divisibility of primes
        # but not unique by shorter sequences
        c2 = [k for k, v in c.items() if v == 1 and 
              all(k[:-i] not in singles for i in range(1, len(k)))]
        
        if len(c2) == 1:
          for x in palindromes:
            if d[x] == list(c2[0]):
              print(f"{p} -> {x}")
              if p != N:
                print("Error: palindrome already known before prime", N)
              exit()  
              
        # add "unique by shorter sequences" to singles
        for x in [k for k, v in c.items() if v == 1]:
          singles.append(x)
      

      Like

  • Unknown's avatar

    Jim Randell 9:40 am on 20 September 2020 Permalink | Reply
    Tags: by: C. S. Mence, flawed   

    Brain-Teaser 8: Cat and dog 

    From The Sunday Times, 16th April 1961 [link]

    In the block of flats where I live there are 4 dogs and 4 cats. The 4 flat numbers, where the dogs are kept, multiplied together = 3,570, but added = my flat number. The 4 numbers, where the cats are kept, multiplied together also = 3,570, but added = 10 less than mine. Some flats keep both a dog and a cat, but there is only one instance of a dog and a cat being kept in adjacent flats.

    At what number do I live, and where are the dogs and cats kept?

    [teaser8]

     
    • Jim Randell's avatar

      Jim Randell 9:41 am on 20 September 2020 Permalink | Reply

      As it is written there are multiple solutions to this puzzle.

      However, we can narrow these down to a single solution (which is the same as the published solution) with the additional condition: “No dogs or cats are kept in flat number 1”.

      This Python program runs in 48ms.

      from enigma import (cproduct, divisor, group, is_disjoint, printf)
      
      # decompose p into k increasing numbers (which when multiplied together give p)
      def decompose(p, k, m=1, s=[]):
        if k == 1:
          if not (p < m):
            yield s + [p]
        else:
          # choose a divisor of p
          for x in divisor(p):
            if not (x < m):
              yield from decompose(p // x, k - 1, x, s + [x])
      
      # collect 4-decompositions of 3570 by sum
      d = group(decompose(3570, 4), by=sum)
      
      # consider possible flat numbers (= sum of dogs)
      for (t, dogs) in d.items():
        # sum of cats is t - 10
        cats = d.get(t - 10, [])
        for (ds, cs) in cproduct([dogs, cats]):
          # some flats keep both a dog and a cat
          if is_disjoint([ds, cs]): continue
          # there is only one instance of a dog and a cat in adjacently numbered flats
          if sum(abs(d - c) == 1 for (d, c) in cproduct([ds, cs])) != 1: continue
          # output solution
          printf("flat={t}: dogs={ds} cats={cs}")
      

      Solution: As set there are 9 possible solutions:

      flat=125, dogs=[1, 2, 17, 105], cats=[1, 5, 7, 102]
      flat=109, dogs=[1, 2, 21, 85], cats=[1, 6, 7, 85]
      flat=99, dogs=[1, 6, 7, 85], cats=[1, 2, 35, 51]
      flat=69, dogs=[1, 7, 10, 51], cats=[1, 6, 17, 35]
      flat=57, dogs=[1, 7, 15, 34], cats=[1, 14, 15, 17]
      flat=55, dogs=[1, 7, 17, 30], cats=[2, 5, 17, 21]
      flat=57, dogs=[2, 3, 17, 35], cats=[1, 14, 15, 17]
      flat=65, dogs=[2, 5, 7, 51], cats=[1, 7, 17, 30]
      flat=45, dogs=[2, 5, 17, 21], cats=[5, 6, 7, 17]

      However, if we eliminate solutions involving flat number 1 then we find only one of these solutions remains:

      flat=45, dogs=[2, 5, 17, 21], cats=[5, 6, 7, 17]

      And this is the published solution. So perhaps the setter “forgot” about 1 when looking at divisors of 3570.

      The following (apology?) was published with Teaser 9:

      Dogs kept at Nos. 2, 5, 17 and 21; cats at 5, 6, 7 and 17. I live at No. 45. This is not a unique solution and no correct entry was rejected.

      We can adjust the program for this variation by setting the m parameter of decompose() to 2 in line 16:

      d = group(decompose(3570, 4, 2), by=sum)
      

      Like

    • Frits's avatar

      Frits 2:04 pm on 20 September 2020 Permalink | Reply

      Limiting flat numbers to 1-199.

       
      from enigma import SubstitutedExpression, join, printf 
      
      #  only one instance of a dog and a cat being kept in adjacent flats  
      adj = lambda li1, li2: sum(1 for x in li1 if x - 1 in li2 or x + 1 in li2)
      
      p = SubstitutedExpression([
          "ABC * DEF * GHI * JKL = 3570",
          "ABC + DEF + GHI + JKL == xyz",
          "MNO * PQR * STU * VWX = 3570",
          "MNO + PQR + STU + VWX + 10 == xyz",
          # numbers are factors of 3570
          "3570 % ABC == 0",
          "3570 % DEF == 0",
          "3570 % GHI == 0",    
          "3570 % JKL == 0",
          "3570 % MNO == 0",
          "3570 % PQR == 0",
          "3570 % STU == 0",
          "3570 % VWX == 0",
          # flat numbers are ascending
          "ABC < DEF",
          "DEF < GHI",
          "GHI < JKL", 
          "MNO < PQR",
          "PQR < STU",
          "STU < VWX",
          # speed up process by limiting range to (1, 199)
          "A < 2", "D < 2", "G < 2", "J < 2",
          "M < 2", "P < 2", "S < 2", "V < 2",
          # only one instance of a dog and a cat being kept in adjacent flats
          "adj([ABC, DEF, GHI, JKL], [MNO, PQR,STU, VWX]) == 1",
          ],
          verbose=0,
          symbols="ABCDEFGHIJKLMNOPQRSTUVWXxyz",
          answer="(ABC, DEF, GHI, JKL, MNO, PQR,STU, VWX, xyz)",
          env=dict(adj=adj), # external functions
          d2i="",            # allow number respresentations to start with 0
          distinct="",       # letters may have same values                     
      )
      
      
      # Solve and print answer
      for (_, ans) in p.solve(): 
        printf("dogs: {p1:<10} - cats: {p2:<11}  Mine={ans[8]}", 
               p1 = join(ans[:4], sep = " "),
               p2 = join(ans[4:8], sep = " "))
      
      # Output:
      #
      # dogs: 1 2 21 85  - cats: 1 6 7 85     Mine=109
      # dogs: 1 6 7 85   - cats: 1 2 35 51    Mine=99
      # dogs: 1 7 10 51  - cats: 1 6 17 35    Mine=69
      # dogs: 1 7 15 34  - cats: 1 14 15 17   Mine=57
      # dogs: 1 7 17 30  - cats: 2 5 17 21    Mine=55
      # dogs: 2 3 17 35  - cats: 1 14 15 17   Mine=57
      # dogs: 2 5 7 51   - cats: 1 7 17 30    Mine=65
      # dogs: 2 5 17 21  - cats: 5 6 7 17     Mine=45
      # dogs: 1 2 17 105 - cats: 1 5 7 102    Mine=125
      

      Like

    • Ellen Napier's avatar

      Ellen Napier 1:03 am on 27 December 2025 Permalink | Reply

      Since “some flats keep both” is plural, I took the number of flats having both
      a dog and a cat to be at least two. That reduces the number of solutions from
      9 to 3.

      An alternative edit (admittedly more complex) would be to change “one instance
      of a cat and a dog” to “one instance of a cat and a cat’s canine companion”,
      which also produces the published solution.

      Like

  • Unknown's avatar

    Jim Randell 9:06 am on 25 August 2020 Permalink | Reply
    Tags: , flawed   

    Teaser 2677: One for each day 

    From The Sunday Times, 12th January 2014 [link] [link]

    George and Martha have been looking into tests for divisibility,  including one for the elusive number seven. George wrote down a thousand-figure number by simply writing one particular non-zero digit a thousand times. Then he replaced the first and last digits by another non-zero digit to give him a thousand-figure number using just two different digits. Martha commented that the resulting number was divisible by seven. George added that it was actually divisible by exactly seven of 2, 3, 4, 5, 6, 7, 8, 9 and 11.

    What were the first two digits of this number?

    Note: This puzzle is marked as flawed, as under the intended interpretation there is no solution.

    [teaser2677]

     
    • Jim Randell's avatar

      Jim Randell 9:06 am on 25 August 2020 Permalink | Reply

      Although the puzzle is flawed, I didn’t have a problem solving it, as I interpreted the “actually” in George’s statement to mean that George was correcting Martha’s statement, so it didn’t really matter if Martha’s statement was true or false. All we needed to do was find a number divisible by exactly seven of the given divisors. Which is what my code does, and it finds a unique solution, so I was happy enough with the puzzle.

      Python’s support for large integers means this one can be solved in a straightforward way. The following program runs in 55ms.

      Run: [ @replit ]

      from enigma import (subsets, printf)
      
      digits = "123456789"
      divisors = (2, 3, 4, 5, 6, 7, 8, 9, 11)
      
      for (a, b) in subsets(digits, size=2, select="P"):
        n = int(a + b * 998 + a)
        ds = list(d for d in divisors if n % d == 0)
        if len(ds) == 7:
          printf("a={a} b={b} [ds={ds}]")
      

      Solution: The first two digits of George’s number are 6 and 3.

      So the 1,000-digit number is 6333…3336. Which is divisible by 2, 3, 4, 6, 8, 9, 11.


      However, apparently the setter intended Martha’s statement to be true, and the number to be divisible by 7 and exactly six of the other divisors. Unfortunately, there is no such number. (As we can see by adding [[ and 7 in ds ]] to the condition on line 9).

      The intended solution was 2777…77772, and the setter mistakenly determined that this was divisible by 8. In fact the number is divisible by only six of the divisors: 2, 3, 4, 6, 7, 11.

      Like

    • Hugh+Casement's avatar

      Hugh+Casement 11:33 am on 26 December 2021 Permalink | Reply

      The puzzle could have stated that the number is an integer multiple of seven of the integers 2 to 12 inclusive.

      However, we don’t need the ability to handle huge numbers (or even a computer).

      We can regard the number as jk followed by 498 blocks of kk followed by kj.
      The test for divisibility by 11 involves taking the alternating positive and negative sum of the digits. jk and kj cancel out, and each kk cancels, so the alternating digit sum is 0: the number is an integer multiple of 11 whatever the values of j and k.

      It cannot be a multiple of 10 since we were told the digits are non-zero.

      A test for divisibility by 7 is to take the alternating positive and negative sum of groups of three digits from the right. If and only if the result is a multiple of 7 is the overall number also a multiple of 7.

      In this case we have a number with j on the left, then 332 blocks of kkk, and kkj on the right.
      The even number of blocks cancel out, leaving kkj − j = kk0 = k × 110.
      That is an integer multiple of 7 only if k = 7.

      If the number is not a multiple of 2 then it cannot be a multiple of 4, 6, 8, or 12.
      If it is not a multiple of 3 then it cannot be a multiple of 6, 9, or 12.
      In order to have seven factors in the list it must be a multiple of both 2 and 3.

      If j = 2 the number is an integer multiple of 2 and 4 (but, as Jim says, not 8).

      So now we know j and k.
      We can regard the number as 27 followed by 332 blocks of 777 followed by 72.
      777 is a multiple of 3, so the digit sum is a multiple of 3 and the number is an integer multiple of 3 (but not of 9). Being a multiple of 3 and 4 it is also a multiple of 12.

      The number is not a multiple of 5, 8, or 9 (nor 10).

      Liked by 1 person

  • Unknown's avatar

    Jim Randell 12:05 pm on 20 August 2020 Permalink | Reply
    Tags: , flawed   

    Teaser 2551: Take nothing for granted 

    From The Sunday Times, 14th August 2011 [link] [link]

    In arithmetic, the zero has some delightful properties. For example:

    ANY + NONE = SAME
    X . ZERO = NONE

    In that sum and product, digits have been replaced with letters, different letters being used for different digits. But nothing should be taken for granted: here the equal signs are only approximations as, in each case, the two sides may be equal or differ by one.

    What is your NAME?

    [teaser2551]

     
    • Jim Randell's avatar

      Jim Randell 12:06 pm on 20 August 2020 Permalink | Reply

      We can use the [[ SubstitutedExpression() ]] solver from the enigma.py library to tackle this puzzle. Unfortunately there are two possible solutions.

      The following run file executes in 159ms.

      Run: [ @repl.it ]

      #! python -m enigma -rr
      
      SubstitutedExpression
      
      "abs(ANY + NONE - SAME) < 2"
      "abs(X * ZERO - NONE) < 2"
      
      --answer="NAME"
      #--answer="SYNONYM" # for a unique answer
      

      Solution: The two possible values for NAME are: 7146 and 7543.

      The possible sums are:

      170 + 7976 = 8146; 6 × 1329 ≈ 7973
      570 + 7973 = 8543; 3 × 2659 ≈ 7976

      In both cases the addition is exact, but the multiplication sums are off by 1.

      If instead, the puzzle had asked the value of SYNONYM the answer would have been unique (= 8079704).

      Like

    • GeoffR's avatar

      GeoffR 3:07 pm on 20 August 2020 Permalink | Reply

      % A Solution in MiniZinc 
      include "globals.mzn";
      
      var 1..9:A; var 1..9:N; var 0..9:Y; 
      var 0..9:O; var 0..9:E; var 1..9:X;
      var 1..9:Z; var 0..9:R; var 1..9:S;  
      var 0..9:M;
      
      constraint all_different([A,N,Y,O,E,X,Z,R,S,M]);
      
      var 100..999: ANY = 100*A + 10*N + Y;
      var 1000..9999: NONE = 1010*N + 100*O + E;
      var 1000..9999: SAME = 1000*S + 100*A + 10*M + E;
      var 1000..9999: ZERO = 1000*Z + 100*E + 10*R + O;
      var 1000..9999: NAME = 1000*N + 100*A + 10*M + E;
      
      constraint ANY + NONE == SAME \/ANY + NONE == SAME + 1
      \/ ANY + NONE == SAME - 1;
      
      constraint X * ZERO == NONE \/  X * ZERO == NONE + 1
      \/  X * ZERO == NONE - 1;
      
      solve satisfy;
      
      output ["NAME = " ++ show(NAME)
      ++ "\n Sum is " ++ show(ANY) ++ " + " ++ show(NONE) 
      ++ " = " ++ show(SAME)
      ++ "\n Product is " ++ show(X) ++ " * " ++ show(ZERO)
      ++ " = " ++ show(NONE)
      ++ "\n SYNONYM = " ++ show(S),show(Y),show(N),show(O),
      show(N),show(Y),show(M)];
      
      % NAME = 7543
      %  Sum is 570 + 7973 = 8543
      %  Product is 6 * 1329 = 7973
      %  SYNONYM = 8079704
      % ----------
      % NAME = 7146
      %  Sum is 170 + 7976 = 8146
      %  Product is 3 * 2659 = 7976
      %  SYNONYM = 8079704
      % ----------
      % ==========
      
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 5:11 pm on 10 July 2020 Permalink | Reply
    Tags: , flawed   

    Teaser 3016: Eureka 

    From The Sunday Times, 12th July 2020 [link] [link]

    Archimedes’ Principle states that the upward force on a floating body equals the weight of water displaced by the body. In testing this, Liam floated a toy boat in a cylindrical drum of water. The boat had vertical sides and took up one tenth of the surface area of the water. He also had some identical ball bearings (enough to fit snugly across the diameter of the drum), which were made of a metal whose density is a single-figure number times that of water.

    Liam loaded the boat with the ball bearings and noted the water level on the side of the drum. When he took the ball bearings out of the boat and dropped them in the water, the water level changed by an amount equal to the radius of a ball bearing.

    How many ball bearings did Liam have?

    This puzzle was not included in the book The Sunday Times Teasers Book 1 (2021).

    [teaser3016]

     
    • Jim Randell's avatar

      Jim Randell 6:26 pm on 10 July 2020 Permalink | Reply

      Suppose there are n ball-bearings, each with a radius of r, then the radius of the cylindrical tank is nr.

      If we take the water level in the tank when the the unladen boat is floating in it to be “low water”, then when the balls are placed in the tank they displace an amount of water equal to their volume: n (4/3) 𝛑 r³.

      The boat still has the same draught, so the water level in the tank increases by:

      [1] (n(4/3)𝛑r³) / (𝛑(nr)²) = (4/3)(r/n)

      \frac{n\left( \frac{4}{3}\pi r^{3} \right)}{\pi \left( nr \right)^{2}}\; =\; \frac{4}{3}\frac{r}{n}

      [Note that the following step is flawed (although appears to be what the setter expects), see my follow-on comment below].

      When the balls are instead placed in the boat, then the weight of the boat is increased by: kn(4/3)𝛑r³ (where the metal of the balls is k times the density of water), and so this weight of water is displaced, so the level of water in the tank (above low water) is:

      [2] (kn(4/3)𝛑r³) / ((9/10)𝛑(nr)²) = (40/27)(kr/n)

      \frac{kn\left( \frac{4}{3}\pi r^{3} \right)}{\frac{9}{10}\pi \left( nr \right)^{2}}\; =\; \frac{40}{27}\frac{kr}{n}

      (the relative density of water is 1).

      The difference between these water levels is r:

      [2] − [1] (40/27)(kr/n) − (4/3)(r/n) = r
      n = (4/27)(10k − 9)

      Only one value of k = 1..9 has (10k − 9) divisible by 27.

      This Python program looks for values of k that give an integer value for n:

      from enigma import (irange, div, printf)
      
      for k in irange(1, 9):
        n = div(40 * k - 36, 27)
        if n is None: continue
        printf("k={k} n={n}")
      

      Solution: There are 12 ball bearings.

      And density of the ball bearings is 9 times that of water. So perhaps they are mostly made of copper (relative density = 8.96).

      Writing:

      40k − 27n = 36
      40k = 9(3n + 4)

      We see that k must be a multiple of 9, and as it must be a single digit the only possibility is k = 9, and so n = 12.

      [This seems to be the expected answer, but see my follow on comment for a more realistic approach].

      Like

      • Jim Randell's avatar

        Jim Randell 9:22 am on 14 July 2020 Permalink | Reply

        In my original treatment, when the water was displaced from loading the boat, it was then added back in to the space around the boat. But unless the water is actually removed, and the boat drops anchor before the displaced water is added back in, the boat will rise as the water is added (we can think of the displaced water being added to the bottom of the tank, rather than the top). So the second water level calculated above is higher than it would be in “real life”.

        The correct calculation is:

        [2] = k×[1] (kn(4/3)𝛑r³) / (𝛑(nr)²) = (4/3)(kr/n)

        \frac{kn\left( \frac{4}{3}\pi r^{3} \right)}{\pi \left( nr \right)^{2}}\; =\; \frac{4}{3}\frac{kr}{n}

        (The cross-sectional area of the boat is immaterial, as the boat rises with the water).

        We then calculate the difference in water levels:

        [2] − [1] (4/3)(kr/n) − (4/3)(r/n) = r
        4(k − 1) = 3n

        So, n is a multiple of 4, and (k − 1) is a multiple of 3:

        n = 4, k = 4
        n = 8, k = 7
        n = 12, k = 10

        For a single digit value of k there are two solutions (although k = 7 would be a more likely relative density for ball bearings [link], so the most reasonable solution would be that there are 8 ball bearings).

        But the relative cross-sectional areas of the boat and the tank don’t seem to matter, so perhaps the setter was expecting the same approach as that I originally gave above.

        Like

      • Jim Randell's avatar

        Jim Randell 10:09 am on 25 March 2023 Permalink | Reply

        The published solution is:

        Teaser 3016
        We apologise that there was not a unique answer.
        4, 8 and 12 were all acceptable.

        Like

    • GeoffR's avatar

      GeoffR 9:02 am on 14 July 2020 Permalink | Reply

      I did a Python programme for a range of ball bearing sizes and the result (as expected) was a constant number of ball bearings. The programme confirmed the difference in water height was the radius of the ball bearing in each case.

      
      from math import pi
      
      # Let rho be density factor of ball bearings c.f. water
      # Let N = number of ball bearings
      
      # ball bearing radius range considered is from 0.25 cm to 2.0 cm
      for r in (0.25, 0.5, 1.0, 1.5, 2.0):  
        for rho in range(1, 10):   
          for N in range(1, 50):
            # calculate radius of tank, area of tank and boat
            tank_rad = N * r
            tank_area = round((pi * tank_rad**2), 3)
            boat_area = round((tank_area / 10), 3)
            
            # calculate weight and volume of N ball bearings 
            wt = rho * 4/3 * pi * r**3 * N
            vol = 4/3 * pi * r**3 * N
      
            # Let h1 be water height change after balls put in tank
            h1 = round((vol / tank_area), 3)
      
            # Let h2 = water height change after balls put in boat
            h2 = round ((wt / (tank_area - boat_area)), 3)
            # check radius of ball bearings = change in water height
            if r == h2 - h1:
              print(f"Ball Bearing Radius = {r} cm. Number of balls = {N} no.")
              print(f"1st height = {h1} cm., 2nd height = {h2} cm., Difference = {h2-h1} cm")
              print()
      
      # Ball Bearing Radius = 0.25 cm. Number of balls = 12 no.
      # 1st height = 0.028 cm., 2nd height = 0.278 cm., Difference = 0.25 cm
      
      # Ball Bearing Radius = 0.5 cm. Number of balls = 12 no.
      # 1st height = 0.056 cm., 2nd height = 0.556 cm., Difference = 0.5 cm
      
      # Ball Bearing Radius = 1 cm. Number of balls = 12 no.
      # 1st height = 0.111 cm., 2nd height = 1.111 cm., Difference = 1.0 cm
      
      # Ball Bearing Radius = 1.5 cm. Number of balls = 12 no.
      # 1st height = 0.167 cm., 2nd height = 1.667 cm., Difference = 1.5 cm
      
      # Ball Bearing Radius = 2 cm. Number of balls = 12 no.
      # 1st height = 0.222 cm., 2nd height = 2.222 cm., Difference = 2.0 cm
      
      
      
      

      Like

    • Dilwyn Jones's avatar

      Dilwyn Jones 11:02 am on 17 July 2020 Permalink | Reply

      I agree with the corrected calculation and a set of possible answers. I wondered if there is an additional constraint – the cross sectional area of a ball bearing must be smaller than the area of the boat, but that is true for all the answers. Then I wondered if all the ball bearings must touch the flat bottom of the boat, which means there must be at least 10 of them ignoring the spaces in between. If instead each bearing fills a square of side 2r, there must be at least 13. However I am speculating, as this information is not given in the problem.

      Like

      • Jim Randell's avatar

        Jim Randell 2:37 pm on 18 July 2020 Permalink | Reply

        I hadn’t given a great deal of thought to the shape of the boat, as I’d reasoned that if the boat was vertical tube with a hole down the middle to stack the balls into, then as long as n² ≥ 10 we could create a boat with the appropriate cross-sectional area. And this is true for all proposed values of n. Although there might be a problem with stability with this design of boat.

        However we know the balls will fit exactly across the diameter of the tank, so if we throw a convex hull around the balls (which would have to be infinitely thin for it to work), then we get a boat that holds all the balls in a line, and it has the added advantage that the boat would be unable to tip over.

        Then the cross-sectional area of the boat as a ratio of the cross-sectional area of the tank is:

        a = (𝛑 + 4(n − 1)) / (n²𝛑)

        Which has the following values:

        n = 4; a = 30.1%
        n = 8; a = 15.5%
        n = 12; a = 10.4%

        Which gets us close to the 10% stipulation at n = 12.

        The same idea, but stacking the balls two rows high gives a boat that will actually fit in the tank (but may tip over):

        a = (𝛑 + 2(n − 2)) / (n²𝛑)

        n = 4; a = 14.2%
        n = 8; a = 7.5%
        n = 12; a = 5.1%

        So with n=8 we can make a boat with a non-zero thickness hull around a cargo hold that can take the balls in a line stacked 2 high.

        Like

  • Unknown's avatar

    Jim Randell 9:33 am on 9 June 2020 Permalink | Reply
    Tags: by: Ernest J Luery, flawed   

    Brain-Teaser 521: [Names and occupations] 

    From The Sunday Times, 6th June 1971 [link]

    There were six. Messrs. Butcher, Carpenter, Draper, Farmer, Grocer and Miller,  who shared the fire-watching on Friday nights — three this week, three the next. By occupation they were (not necessarily respectively) a butcher, a carpenter, a draper, a farmer, a grocer and a miller.

    Incidents were few and far between, until that Saturday morning when they found the “log” book signed by the Acting Deputy Assistant something or other, as follows: “All three present and fast asleep”.

    Something had to be done about it: they decided to watch, to play whist, and to keep awake in the future. It was arranged thus: four did duty this week, next week two stood down and two others came in, and so on. Each did two turns in three weeks.

    On the first Friday the carpenter, the draper, the farmer and the miller watched. Next week Mr Carpenter, Mr Draper, Mr Farmer and Mr Grocer played. On the third occasion Mr Butcher played against Mr Grocer, Mr Farmer against the butcher, and the miller against the draper. Each night the four cut for partners and kept them till morning.

    If Mr Carpenter’s occupation is the same as the name of the one whose occupation is the same as the name of the one whose occupation is the same as the one whose occupation is the same as the name of the miller:

    What is Mr Miller’s occupation?

    As presented this puzzle has no solutions. In the comments I give a revised version that does have a unique answer.

    This puzzle was originally published with no title.

    [teaser521]

     
    • Jim Randell's avatar

      Jim Randell 9:33 am on 9 June 2020 Permalink | Reply

      I thought the tricky bit in this puzzle would be detangling the long obfuscated condition at the end (and decide if there was a “the name of” missing from it). But it turns out we can show that there are no solutions before we get that far, so the puzzle is flawed.

      In week 3 we have the following pairs (Mr Butcher + Mr Grocer), (Mr Farmer + the butcher), (the miller + the draper).

      But there are only four people (i.e. two pairs), so one of the pairs is repeated. The middle one doesn’t overlap with either of the outer two, so the outer two must refer to the same pair. i.e. (Mr Butcher + Mr Grocer) = (the miller + the draper).

      In week 2 we had Mr Carpenter, Mr Draper, Mr Farmer and Mr Grocer. And Mr Farmer and Mr Grocer stayed on for week 3, which means they can’t have done week 1.

      The jobs missing from week 1 are the butcher and the grocer, so: (Mr Farmer + Mr Grocer) = (the butcher + the grocer).

      But Mr Grocer cannot be one of (the miller + the draper) and also one of (the butcher + the grocer).

      So the described situation is not possible.


      However if we change the names in the second week to match the jobs from the first week (which I think makes for a more pleasing puzzle), and also insert the missing “the name of” into the final obfuscated condition we get the following revised puzzle:

      On the first Friday the carpenter, the draper, the farmer and the miller watched. Next week Mr Carpenter, Mr Draper, Mr Farmer and Mr Miller played. On the third occasion Mr Butcher played against Mr Grocer, Mr Farmer against the butcher, and the miller against the draper. Each night the four cut for partners and kept them till morning.

      If Mr Carpenter’s occupation is the same as the name of the one whose occupation is the same as the name of the one whose occupation is the same as the name of the one whose occupation is the same as the name of the miller:

      What is Mr Miller’s occupation?

      Then we get a puzzle that does have solutions (although not the same as the published solution).

      The following Python program runs in 54ms.

      Run: [ @repl.it ]

      from enigma import (irange, subsets, multiset, map2str, printf)
      
      # labels for the names and jobs
      labels = (B, C, D, F, G, M) = irange(0, 5)
      
      # check the schedule for the 3 weeks
      def check(w1, w2, w3):
        m = multiset()
        for w in (w1, w2, w3):
          w = set(w)
          # 4 different people each week
          if len(w) != 4: return False
          m.update_from_seq(w)
        # each person does 2 duties over the 3 weeks
        return all(v == 2 for v in m.values())
      
      # map: job -> name
      for n in subsets(labels, size=len, select="P"):
      
        # Week 1 = carpenter, draper, farmer, miller
        w1 = [n[C], n[D], n[F], n[M]]
        # Week 2 = Carpenter, Draper, Farmer, Miller
        w2 = [C, D, F, M] # NOT: [C, D, F, G]
        # Week 3 = Butcher + Grocer, Farmer + butcher, miller + draper
        # so: Butcher + Grocer = miller + draper
        if not(set([B, G]) == set([n[M], n[D]])): continue
        w3 = [B, G, F, n[B]]
      
        if not check(w1, w2, w3): continue
      
        # "Mr Carpenter's occupation is the same as the name of the one
        # whose occupation is the same as the name of the one whose
        # occupation is the same as the [name of] one whose occupation is
        # the same as the name of the miller"
        if not(n[n[n[n[n[M]]]]] == C): continue
      
        # output the map
        names = ("Butcher", "Carpenter", "Draper", "Farmer", "Grocer", "Miller")
        jobs = list(x.lower() for x in names)
        printf("{s}", s=map2str(((names[n], j) for (n, j) in zip(n, jobs)), sep="; ", enc=""))
      

      Solution: Mr Miller is the carpenter.

      There are three ways to assign the jobs to the names:

      Butcher=draper; Carpenter=butcher; Draper=farmer; Farmer=grocer; Grocer=miller; Miller=carpenter
      Butcher=miller; Carpenter=butcher; Draper=farmer; Farmer=grocer; Grocer=draper; Miller=carpenter
      Butcher=miller; Carpenter=farmer; Draper=butcher; Farmer=grocer; Grocer=draper; Miller=carpenter

      Like

  • Unknown's avatar

    Jim Randell 8:11 am on 2 June 2020 Permalink | Reply
    Tags: , , flawed   

    Teaser 2566: A fulfilling strategy 

    From The Sunday Times, 27th November 2011 [link] [link]

    I drove down a road with a number of petrol stations whose locations I saw on my map. I decided to check the price at the first station then fill up when I found one offering a lower price (or, failing that, the last one).

    When I got home I noticed that I could arrange the prices (in pence per litre) into an ascending sequence of consecutive whole numbers of pence, plus 0.9p (i.e. 130.9p, 131.9p, 132.2p, etc). I also worked out the average price that I would expect to pay using this strategy, if I were to encounter this set of prices in an unknown order, and I was surprised to find that this value turned out to be a whole number of pence per litre.

    How many petrol stations were there?

    When the puzzle was originally published in The Sunday Times it had been edited into a form that meant there were no solutions. Here I have rephrased the middle paragraph so that it works as the setter originally intended.

    [teaser2566]

     
    • Jim Randell's avatar

      Jim Randell 8:12 am on 2 June 2020 Permalink | Reply

      (See also: Teaser 2988).

      Here is a program that calculates the result directly. It runs in 50ms.

      Run: [ @replit ]

      from enigma import (subsets, irange, inf, factorial, div, printf)
      
      # strategy, take the first amount lower than the first n items
      def strategy(s, n):
        t = min(s[:n])
        for x in s[n:]:
          if x < t: break
        return x
      
      # play the game with k items
      def play(k):
        # collect total amount
        t = 0
        # consider possible orderings of the items
        ps = list(1299 + 10 * p for p in irange(1, k))
        for s in subsets(ps, size=k, select="P"):
          t += strategy(s, 1)
        return t
      
      # consider numbers of items
      for k in irange(2, inf):
        t = play(k)
        # calculate the average expected price (in 10th pence)
        d = factorial(k)
        p = div(t, d)
        if p is not None and p % 10 == 0:
          printf("k={k} -> p={p}")
          break
      

      Solution: There were 5 petrol stations.

      And the expected average fuel price was 132.0 pence.

      It doesn’t actually matter what the prices actually are, all the petrol stations could adjust their prices by the same whole number of pence, and the expected average price would be adjusted by the same amount.


      Analytically:

      As determined in Teaser 2988 we can use the formula:

      S(n, k) = ((2n + 1)k − n(n + 1)) (k + 1) / 2(n + 1)k

      To determine the mean expected value of choosing from k boxes with values from 1..k, using the strategy of picking the next box that is better than any of the first n boxes (or the last box if there are no boxes better than the first).

      In this case n = 1:

      S(1, k) = (3k − 2) (k + 1) / 4k

      If we award ourselves a prize of value k for selecting the cheapest fuel, and a prize of value 1 for selecting the most expensive fuel, then we have the same situation as in Teaser 2988, and if p is expected average prize value, then the corresponding expected average fuel price is (130.9 + k − p).

      And k is an integer, so in order to make the expected average fuel price a whole number of pence we are looking for expected average prize value that is an integer plus 0.9.

      i.e. when the value of 10 S(1, k) is an integer with a residue of 9 modulo 10.

      10 S(1, k) = (15k + 5) / 2 − (5 / k)

      When k is odd, the first part gives us a whole number, so we would also need the (5 / k) part to give a whole number. i.e. k = 1, 5.

      When k is even, the first part gives us an odd number of halves, so we also need (5 / k) to give an odd number of halves. i.e. k = 2, 10.

      And we are only interested in values of k > 1, so there are just 3 values to check:

      k = 5: 10 S(1, k) = 39
      k = 2: 10 S(1, k) = 15
      k = 10: 10 S(1, k) = 77

      The only value for k that gives a residue of 9 modulo 10 is k = 5.

      And in this case our expected average prize is p = 3.9 so our expected average fuel price is 132.0 pence.

      Like

  • Unknown's avatar

    Jim Randell 10:54 am on 7 May 2020 Permalink | Reply
    Tags: , flawed   

    Teaser 2869: Cubic savings 

    From The Sunday Times, 17th September 2017 [link] [link]

    In 2009 George and Martha had a four-figure number of pounds in a special savings account (interest being paid into a separate current account). At the end of the year they decided to give some of it away, the gift being shared equally among their seven grandchildren, with each grandchild getting a whole number of pounds. At the end of the following year they did a similar thing with a different-sized gift, but again each grandchild received an equal whole number of pounds. They have repeated this procedure at the end of every year since.

    The surprising thing is that, at all times, the number of pounds in the savings account has been a perfect cube.

    What is the largest single gift received by any grandchild?

    [teaser2869]

     
    • Jim Randell's avatar

      Jim Randell 10:54 am on 7 May 2020 Permalink | Reply

      This puzzle is marked as flawed, as there are two possible solutions.

      I assumed the number of grandchildren remained constant (at 7) during the eight years in question (2009 – 2016).

      The amounts in the savings account are perfect cubes, that differ by multiples of 7, so we can collect cubes by their residue modulo 7, and consider the sets for each residue to look for 9 amounts that satisfy the remaining conditions.

      This Python program runs in 76ms.

      Run: [ @replit ]

      from enigma import (group, powers, mod, subsets, tuples, printf)
      
      # group the cubes (up to 4 digits) in descending order, by their residue mod 7
      cubes = group(powers(21, 1, 3, step=-1), by=mod(7))
      
      # choose values for the eight gifts made (2009 - 2016)
      for s in cubes.values():
        for vs in subsets(s, size=9):
          if s[0] < 1000: continue
          # and calculate the sequence of gifts
          gs = tuple((a - b) // 7 for (a, b) in tuples(vs, 2))
          if len(set(gs)) != len(gs): continue # gift amounts are all different
          # output solutions
          m = max(gs)
          printf("{vs} -> {gs}, max = {m}")
      

      Solution: There are two solutions. The largest amount is received by a grandchild is £ 292, or £ 388.

      If we start with 5832 (= 18³) in the savings account, and then give presents of (248, 103, 292, 86, 31, 64, 8, 1) to each grandchild then the amounts remaining in the savings account are:

      5832 (= 18³)
      4096 (= 16³)
      3375 (= 15³)
      1331 (= 11³)
      729 (= 9³)
      512 (= 8³)
      64 (= 4³)
      8 (= 2³)
      1 (= 1³)

      However, starting with 8000 (= 20³) and giving (163, 278, 388, 67, 104, 112, 13, 14), leaves amounts of:

      8000 (= 20³)
      6859 (= 19³)
      4913 (= 17³)
      2197 (= 13³)
      1728 (= 12³)
      1000 (= 10³)
      216 (= 6³)
      125 (= 5³)
      27 (= 3³)

      One way to rescue the puzzle is to exclude 1 as an amount given to the grandchildren (or remaining in the account).

      Another way is to require that none of the amounts given to any grandchild is itself a perfect cube.

      Either of these restrictions eliminate the first solution, leaving a unique answer of £ 388.

      Like

    • GeoffR's avatar

      GeoffR 8:28 am on 10 May 2020 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";
      
      % Yearly account balances
      var 1000..9999: S1; var 1..9999: S2; var 1..9999: S3;
      var 1..9999: S4; var 1..9999: S5; var 1..9999: S6;
      var 1..9999: S7; var 1..9999: S8; var 1..9999: S9;
      
      % yearly gifts 2009 - 2016
      var 1..1400: G1; var 1..999: G2; var 1..999: G3;
      var 1..999: G4; var 1..999: G5; var 1..999: G6;
      var 1..999: G7; var 1..999: G8; 
      
      % All yearly gifts are different values
      constraint all_different ([G1, G2, G3, G4, G5, G6, G7, G8]);
      
      % Set of cubes up to a maximum of four digits
      set of int: cube = {n * n * n | n in 1..21};
      
      % S1 is largest yearly account balance
      constraint increasing([S9,S8,S7,S6,S5,S4,S3,S2,S1]);
      
      % All yearly account balances are cubes
      constraint S1 in cube /\  S2 in cube /\  S3 in cube 
      /\ S4 in cube /\  S5 in cube /\  S6 in cube
      /\ S7 in cube /\  S8 in cube /\ S9 in cube;
      
      % Yearly amounts to distribute amongst seven grandchildren
      constraint (S1 - S2) mod 7 == 0 /\ (S2 - S3) mod 7 == 0 /\ 
      (S3 - S4) mod 7 == 0 /\ (S4 - S5) mod 7 == 0
      /\ (S5 - S6) mod 7 == 0 /\ (S6 - S7) mod 7 == 0 
      /\ (S7 - S8) mod 7 == 0 /\ (S8 - S9) mod 7 == 0;
      
      % Yearly total gifts to each of seven grandchildren
      constraint G1 == (S1 - S2) div 7 /\ G2 == (S2 - S3) div 7
      /\ G3 == (S3 - S4) div 7 /\ G4 == (S4 - S5) div 7
      /\ G5 == (S5 - S6) div 7 /\ G6 == (S6 - S7) div 7
      /\ G7 == (S7 - S8) div 7 /\ G8 == (S8 - S9) div 7;
      
      % Maximum yearly gift
      var 10..1000: maxv;
      maxv = max([G1, G2, G3, G4, G5, G6, G7, G8]);
       
      solve satisfy;
      
      output ["Yearly account balances: " ++ 
      show([S1, S2, S3, S4, S5, S6, S7, S8, S9])] ++ 
      ["\nYearly gifts(£): " ++ show ([G1, G2, G3, G4, G5, G6, G7, G8])]
      ++ ["\nMax gift = " ++ show(maxv)] ;
      
      % Yearly account balances: [5832, 4096, 3375, 1331, 729, 512, 64, 8, 1]
      % Yearly gifts(£): [248, 103, 292, 86, 31, 64, 8, 1]
      % Max gift = 292
      % ----------
      % Yearly account balances: [8000, 6859, 4913, 2197, 1728, 1000, 216, 125, 27]
      % Yearly gifts(£): [163, 278, 388, 67, 104, 112, 13, 14]
      % Max gift = 388
      % ----------
      % ==========
      
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 12:50 pm on 5 November 2019 Permalink | Reply
    Tags: , , flawed   

    Brain-Teaser 508: [Family birthdays] 

    From The Sunday Times, 7th March 1971 [link]

    Grandma said: “Grandpa and I share between 100 and 120 years of age, being both over 50 years old. The total ages of our family (our son and his children — all of different age years, and over 12 months) exactly equal [my own age. On the same day next year they will exactly equal] Grandpa’s age.”

    “At present, Grandpa’s age is divisible by the age of only one child, but in one year’s time it will be divisible by the separate ages of three children, and also by the number in our family, while my own age will be divisible by the age of one child only (unity always excluded).”

    “During the year ahead on just one day in May, Grandpa’s age will be divisible by that of our son, whose birthday is earlier.”

    “From Grandpa downwards, what are our ages?”

    The following apology was published with Brain-Teaser 511:

    It is regretted that by a printing error the following words were omitted after “exactly equal”: “my own age. On the same day next year they will exactly equal”.

    I have inserted the missing text in the puzzle above.

    This puzzle was originally published with no title.

    [teaser508]

     
    • Jim Randell's avatar

      Jim Randell 2:22 pm on 5 November 2019 Permalink | Reply

      I wrote a program to solve the puzzle as originally stated (without the additional text) and found 15 solutions.

      So I created a MiniZinc model that makes it easy to play around with variations on the puzzle.

      When the constraints arising from the missing text are incorporated we get a single solution.

      %#! minizinc -a
      
      % grandpa and grandma are aged between 51 and 69
      var 51..69: gp;
      var 51..69: gm;
      
      % but the total is not more than 120
      constraint not(gp + gm > 120);
      
      % son's age
      var 18..51: son;
      
      % kids ages (0 for no kid)
      array[1..10] of var 0..16: kids;
      
      % kids are descending order, and all different
      constraint forall (i in 2..10) (kids[i] > 0 -> kids[i - 1] > kids[i]);
      
      % son + total of kids ages = gm [originally was = gp]
      constraint son + sum(kids) = gm;
      
      % son + total of kids ages in 1 year = gp, so: gp - gm = number of children
      % [originally this condition was omitted]
      constraint sum (i in 1..10) (kids[i] > 0) = gp - gm;
      
      % exactly 1 kid divides gp
      constraint sum (i in 1..10) (kids[i] > 1 /\ gp mod kids[i] = 0) = 1;
      
      % but exactly 3 kids divide gp in 1 year
      constraint sum (i in 1..10) (kids[i] > 0 /\ (gp + 1) mod (kids[i] + 1) = 0) = 3;
      
      % and exactly 1 kid divides gm in 1 year
      constraint sum (i in 1..10) (kids[i] > 0 /\ (gm + 1) mod (kids[i] + 1) = 0) = 1;
      
      % also the number of kids + 1 divides into gp in 1 year
      constraint (gp + 1) mod (1 + sum (i in 1..10) (kids[i] > 0)) = 0;
      
      % (son + 1) divides gp
      constraint gp mod (son + 1) = 0;
      
      % at least 16 years between generations
      constraint son + 16 < min([gp, gm]);
      constraint max(kids) + 16 < son;
      
      solve satisfy;
      

      And we can format the output with Python 3 by using the minizinc.py wrapper:

      from minizinc import MiniZinc
      
      for (gp, gm, son, kids) in MiniZinc("teaser508.mzn").solve(result="gp gm son kids"):
        kids = list(x for x in kids.values() if x > 0)
        print(f"Grandpa = {gp}; Grandma = {gm}; Son = {son}; Children = {kids}")
      

      So the answer to the corrected puzzle is:

      Solution: Grandpa = 62; Grandma = 56; Son = 30; Children = 8, 6, 5, 4, 2, 1.

      Without the constraints to enforce a 16 year gap between generations we can have a further solution (with 7 children):

      Grandpa = 63; Grandma = 56; Son = 20; Children = 15, 6, 5, 4, 3, 2, 1

      Like

  • Unknown's avatar

    Jim Randell 9:41 am on 16 October 2019 Permalink | Reply
    Tags: , flawed   

    Teaser 2825: Twin sets 

    From The Sunday Times, 13th November 2016 [link] [link]

    The twins Wunce and Repete each made a list of positive perfect squares. In Wunce’s list each of the digits 0 to 9 was used exactly once, whereas in Repete’s list each of the digits was used at least once.

    Wunce commented that the sum of his squares equalled their year of birth, and Repete responded by saying that the sum of his squares was less than the square of their age.

    What is the sum of Wunce’s squares, and what is the sum of Repete’s?

    As stated there are multiple potential solutions to the puzzle. In the comments I give some additional conditions that allow a unique solution to be found (which is the same as the published solution).

    [teaser2825]

     
    • Jim Randell's avatar

      Jim Randell 9:42 am on 16 October 2019 Permalink | Reply

      As originally stated there are multiple solutions to this puzzle.

      I made the following additional suppositions in order to allow a unique solution to be arrived at.

      1. the puzzle is set on/after the twins birthday in 2018;
      2. the lists do not contain repeats;
      3. the squares are greater than 1.

      The following Python program then finds the unique solution in 281ms.

      Run: [ @repl.it ]

      from enigma import irange, isqrt, filter2, is_duplicate, arg, printf
      
      # Y = year the puzzle is set (which apparently should be 2018)
      Y = arg(2018, 0, int)
      # m = minimum allowable square (the root of the square is used)
      m = arg(2, 1, int)
      printf("[Y = {Y}, m={m}]")
      
      # squares (as strings, without repeated digits)
      (_, squares) = filter2(is_duplicate, (str(i * i) for i in irange(m, isqrt(Y))))
      
      # for Wunce find a pan-digital subset (without repeated digits)
      # ss = squares to consider
      # s = squares used so far
      # ds = digits used so far
      def solve1(ss, s=[], ds=set()):
        # are we done?
        if len(ds) == 10:
          yield list(int(x) for x in s)
        else:
          # chose the next element
          for (i, x) in enumerate(ss):
            if ds.intersection(x): continue
            yield from solve1(ss[i + 1:], s + [x], ds.union(x))
      
      # for Repete find a pan-digital set of squares (allowing repeated digits)
      # below a given total
      # n = largest square to consider
      # t = sum of squares must be less than this
      # s = squares used so far
      # ds = digits used so far
      def solve2(n, t, s=[], ds=set()):
        # are we done?
        if len(ds) == 10:
          yield s
        # choose the next element
        for i in irange(n, m, step=-1):
          i2 = i * i
          if i2 < t:
            yield from solve2(i - 1, t - i2, s + [i2], ds.union(str(i2)))
      
      # find sequences for Wunce
      for s1 in solve1(squares):
        t1 = sum(s1)
        printf("Wunce: total = {t1}, squares = {s1}")
      
        # calculate the age
        age = Y - t1
        age2 = age * age
        printf("age = {age}, age^2 = {age2}")
      
        # find sequences for Repete
        for s2 in solve2(age - 1, age2):
          t2 = sum(s2)
          printf("Repete: total = {t2}, squares = {s2}")
      

      Solution: The sum of Wunce’s squares is 1989. The sum of Repete’s squares is 831.

      Wunce’s list of squares is (324, 576, 1089) = (18², 24², 33²).

      The sum of which is 1989. So in 2018 the twins would be 29.

      Repete’s list of squares is (4, 9, 25, 36, 81, 100, 576) = (2², 3², 5², 6², 9², 10², 24²).

      The sum of which is 831. Which is less than 841 = 29².

      If we allow 1 in the list of squares then the sum of Repete’s list could be 832. And there are further possibilities if squares in the list are allowed to be repeated.


      The published solution is as follows:

      The sum of Wunce’s squares was 1989. We apologise that this Teaser needed to have been published in 2018 or later in order to resolve the sum of Repete’s squares (the intended answer was 831). All entries showing a correct answer for the first part of the Teaser will be included in the prize draw.

      Like

    • Frits's avatar

      Frits 1:43 pm on 20 October 2020 Permalink | Reply

      Same three assumptions.

      from enigma import nsplit, flatten
      from itertools import combinations as comb
      
      # contains all digits 0-9
      alldigits = lambda li: all(i in flatten([nsplit(x) for x in li]) 
                                 for i in range(0, 10))
      
      sq = [i*i for i in range(2, 45)]
      
      # check squares for Wunce
      for j in range(3, 6):
        # digit 7 only occurs first at sq[22] (576)
        # so pick some squares < 576 and at least one >= 576
        for j1 in range(1, j):
          for p1 in comb(sq[:22], j1):
            for p2 in comb(sq[22:], j - j1):
              p = p1 + p2
             
              if sum(p) not in range(1900, 2020): continue
              if sum(len(str(x)) for x in p) != 10: continue
              if not alldigits(p): continue
              
              age = 2018 - sum(p)
              limit = age * age
              
              space = limit - 576
              if space < 0: continue
              
              # we may only pick one or two squares from group 576, 625, ....
              fromHighest = 1 if space < 625 else 2
              
              # highest index with square smaller than limit and 2 smallest squares
              h2 = max([i for i, x in enumerate(sq) if x <= limit - 4 - 9])
              
              # check squares for Repete
              for k in range(3, 10):
               for j3 in range(1, fromHighest + 1):
                  for q2 in comb(sq[22:h2+1], j3):
                    picked = sum(q2)
                    # highest index with square smaller than limit minus q2 entries
                    h1 = max([i for i, x in enumerate(sq) if x <= limit - picked])
                    
                    for q1 in comb(sq[:h1+1], k - j3):
                      q = q1 + q2
                      if not alldigits(q): continue
                      if sum(q) >= age*age: continue
                      print("sum Wunce's", sum(p), p)
                      print("sum Repete's", sum(q), q)
                      print("Age", age)
      

      Like

  • Unknown's avatar

    Jim Randell 10:54 am on 27 September 2019 Permalink | Reply
    Tags: , flawed   

    Brain-Teaser 502: [Duplicated leaves] 

    From The Sunday Times, 17th January 1971 [link]

    A publisher friend of mine told me the following improbable story. He dreamt that on his shelves he had a collection of twelve books of the same edition of the same title. The curious thing about these books was this:

    The book, as published, ran to 300 pages, but eleven of the books on his shelves had each been bound with duplicate leaves inserted. The number of leaves thus duplicated was different in each volume, all except two being even numbers. They went in ascending order from the book on the left (Volume I), the highest being twenty extra leaves in Volume XI.

    The end book on the right (Volume XII) had 200 pages missing. By a strange coincidence, the duplicated sections from the other volumes exactly filled these gaps. In the reconstituted Volume XII the middle pages (143 to 158) came from the middle volume of the faulty books, while half the duplicated pages came before these and an equal number in the latter half of the volume.

    How many pages were duplicated in Volume IV?

    This puzzle was originally published with no title.

    [teaser502]

     
    • Jim Randell's avatar

      Jim Randell 10:55 am on 27 September 2019 Permalink | Reply

      Assuming that 1 “leaf” consists of 2 “pages” (the “front” (odd numbered) page and “back” (even numbered) page).

      We know vol XII has 200 missing pages (= 100 missing leaves), and each is accounted for (exactly) by the duplicate leaves in vols I – XI.

      Of the 100 duplicate leaves vol XI has 20 of them, so the remaining volumes have 80 duplicate leaves between them.

      This Python program examines this scenario. It runs in 104ms.

      from enigma import (irange, printf)
      
      # decompose total t into k different ascending numbers, min value m
      def decompose(t, k, m=1, s=[]):
        if k == 1:
          if not (t < m):
            yield s + [t]
        else:
          for x in irange(m, t - (k - 1) * m):
            yield from decompose(t - x, k - 1, x + 1, s + [x])
      
      # there are 80 extra leaves amongst vols I - X
      for vs in decompose(80, 10, 1):
        # vol VI has (at least) 8 extra leaves
        if vs[5] < 8: continue
        # and vol XI has exactly 20 extra leaves
        if vs[-1] > 19: continue
        vs.append(20)
      
        # exactly 2 are odd
        if not (sum(x % 2 == 1 for x in vs) == 2): continue
      
        # output the number of duplicate leaves for each volume
        printf("{vs}")
      

      This seems to give 4 possibilities for the numbers of duplicate leaves:

      [1, 2, 3, 4, 6, 8, 10, 12, 16, 18, 20]
      [1, 2, 4, 5, 6, 8, 10, 12, 14, 18, 20]
      [1, 2, 4, 6, 7, 8, 10, 12, 14, 16, 20]
      [2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 20]

      If we’d been asked for the number of duplicate leaves (or pages) in vols VII or VIII there would be a unique solution (10 leaves for vol VII; 12 leaves for vol VIII), but not for vol IV (we have options for 4, 5, 6 duplicate leaves).

      So we need to try an untangle the condition:

      “In the reconstituted Volume XII the middle pages (143 to 158) came from the middle volume of the faulty books, while half the duplicated pages came before these and an equal number in the latter half of the volume.”

      So vol VI must have (at least) 8 duplicate leaves. Which it does in each of our possibilities, so that doesn’t help us.

      The rest of it either doesn’t make sense, or doesn’t seem to be useful.

      “half the duplicate pages” is 50 leaves, so 50 of the duplicate leaves end up making up some of pages 1-142 of vol XII.

      It then goes on to say “and an equal number” (presumably another 50 leaves) “in the latter half of the volume” (presumably pages 151-300), which seems to account for 104 of the 100 missing leaves. So that can’t be right.

      Perhaps it meant “…half the remaining duplicated pages…”, but that just tells us that 46 of the duplicate leaves are used for pages 1-142, and the other 46 are used for pages 159-300, which as we have 92 duplicate leaves to distribute doesn’t seem to help either.

      Another possibility is to ignore the final condition, and take a strict reading of “eleven of the books on his shelves had each been bound with duplicate leaves inserted”, to mean that each book has at least 2 duplicate leaves. This removes the first 3 of the possibilities, leaving:

      I→2, II→3, III→4, IV→5, V→6, VI→8, VII→10, VIII→12, IX→14, X→16, XI→20

      As the only remaining solution, so vol IV has 5 duplicate leaves, and hence 10 duplicate pages. (Which is the published solution).

      We can modify line 13 of the program to [[ decompose(80, 10, 2) ]] to get this single solution.

      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