Updates from Jim Randell Toggle Comment Threads | Keyboard Shortcuts

  • Unknown's avatar

    Jim Randell 9:56 am on 27 February 2022 Permalink | Reply
    Tags: by: N. M. Smith   

    A Holiday Brain Teaser: Mental arithmetic 

    From The Sunday Times, 3rd August 1958 [link]

    “My wife and I have two nieces staying with us”, said the Professor to his Assistant. “Yesterday, at lunch, I noticed that the sum of the ages of the three ladies was exactly twice your age; and, the product of their ages was 2,450. I am talking, by the way, only in terms of whole numbers of years. Can you tell me how old my nieces are?”

    After a few moments’ thought, the Assistant said, “You have not given me quite enough information”.

    “You are right”, said the Professor. But when I tell you that the luncheon was to celebrate my birthday, and that I was the oldest of the four present, you have all the information you need”.

    How old were the Professor, and his wife?

    This one of the occasional Holiday Brain Teasers published in The Sunday Times prior to the start of numbered Teasers in 1961. A prize of £5 was offered.

    [teaser-1958-08-03] [teaser-unnumbered]

     
    • Jim Randell's avatar

      Jim Randell 9:58 am on 27 February 2022 Permalink | Reply

      We can look for decompositions of 2450 into three (reasonable) factors, and we are looking for decompositions that give the same even sum (which is twice the assistant’s age).

      The assistant (presumably) knows his own age, but we can work it out, because there is only one viable age that gives multiple decompositions.

      Knowing the professor is the oldest must allow us to eliminate all but one of the candidate ages. This means the professors age must be more than the largest factor in the first candidate (sorted by largest factor = wife’s age) and not more than the largest factor in the second candidate (otherwise that would become a possibility).

      This Python program runs in 47ms.

      Run: [ @replit ]

      from enigma import (divisors_tuples, div, Record, group, attr, printf)
      
      # generate possible ages (nieces = a, b, wife = c, assistant = d)
      def generate():
        for (a, b, c) in divisors_tuples(2450, 3):
          if c > 120: continue
          d = div(a + b + c, 2)
          if d is None: continue
          yield Record(a=a, b=b, c=c, d=d)
      
      # group ages together by assistant's age (d)
      d = group(generate(), by=attr('d'))
      
      # find d values that are ambiguous
      for (k, vs) in d.items():
        if len(vs) < 2: continue
        # sort the values by wife's age (c)
        vs.sort(key=attr('c'))
        # the answer must be the first record
        r = vs[0]
        # professor's age must be larger than wife's age in first record,
        # and not more than wife's age in second record
        prof = [r.c + 1, vs[1].c]
        printf("assistant={k} -> wife={r.c} prof={prof} [nieces=({r.a}, {r.b})]")
      

      Solution: The professor is 50. His wife is 49.

      And the nieces are 5 and 10. The assistant is 32.

      Like

  • Unknown's avatar

    Jim Randell 4:26 pm on 25 February 2022 Permalink | Reply
    Tags:   

    Teaser 3101: Lap progression 

    From The Sunday Times, 27th February 2022 [link] [link]

    In a charity fundraising drive, two friends completed laps of their local track. Alan, a cyclist, raised £1 for his first lap, £2 for the second, £3 for the third and so on, with each extra lap earning £1 more than the prior. Bob, who walks, raised £1 for his first lap, £2 for the second, £4 for the third and so on, with each extra lap earning double the prior. Starting together, they travelled at constant speeds, and finished their last lap simultaneously.

    After they had added up their totals, they were surprised to find they each raised an identical four-figure sum.

    Including the beginning and end of their drive, how many times did Alan and Bob cross the lap start-finish line together?

    [teaser3101]

     
    • Jim Randell's avatar

      Jim Randell 5:28 pm on 25 February 2022 Permalink | Reply

      We are looking for 4-digit numbers that are both triangular and one less than a power of 2.

      This Python program runs in 46ms.

      Run: [ @replit ]

      from enigma import (irange, inf, is_triangular, gcd, printf)
      
      # consider powers of 2
      p = 1
      for n in irange(1, inf):
        p *= 2
        t = p - 1
        # we are looking for a 4-digit total
        if t < 1000: continue
        if t > 9999: break
        # that is also triangular
        r = is_triangular(t)
        if r is None: continue
        # calculate number of coincident boundaries
        g = gcd(n, r) + 1
        printf("{t} = 2^({n})-1 = T[{r}] -> {g} times")
      

      Solution: Alan and Bob were together at the start/finish line 7 times.


      Manually:

      There are only four 4-digit numbers that are 1 less than a power of 2:

      1023 = 2^10 − 1
      2047 = 2^11 − 1
      4095 = 2^12 − 1
      8191 = 2^13 − 1

      The triangular root of a number is given by trirt(x) = (√(8x + 1) − 1) / 2, and can be easily calculated for these 4 numbers:

      trirt(1023) = 44.735…
      trirt(2047) = 63.486…
      trirt(4095) = 90
      trirt(8191) = 127.493…

      Hence the solution occurs when Bob completes 12 laps and Alan 90 laps.

      We can then calculate the number of times they are at the start/finish together:

      gcd(12, 90) + 1 = 7


      The puzzle also works (but with a different answer) if Bob’s progression is the odd numbers, 1, 3, 5, 7, 9, ….

      Like

    • GeoffR's avatar

      GeoffR 12:22 pm on 2 March 2022 Permalink | Reply

      
      % A Solution in MiniZinc
      include "globals.mzn";
      
      % Four figure sums for Alan and Bob
      var 1000..9999:A;  
      var 1000..9999:B;
      
      var 45..140:a; % triangular number range
      var 10..13:b;  % power of 2 range
      var 1..13:laps; % times crossing start/finish line together
      
      constraint A == a * (a + 1) div 2 ;
      constraint B =  pow(2, b) - 1 ;
      constraint A == B;
      
      % reusing Hakan's GCD Function
      function var int: gcd(var int: x, var int: y) =
        let {
          int: p = min(ub(x),ub(y));
          var 1..p: g;
          constraint
             exists(i in 1..p) (
                x mod i = 0 /\ y mod i = 0
                /\
                forall(j in i+1..p) (
                   not(x mod j = 0 /\ y mod j = 0)
                ) /\ g = i);
        } in g;
        
      % Times Alan and Bob cross the lap start-finish line together
      constraint laps == gcd(a, b) + 1;
      
      solve satisfy;
      
      output ["No. of coincident start/finish crossings = " ++ show(laps)];
      
      

      Liked by 1 person

  • Unknown's avatar

    Jim Randell 9:48 am on 24 February 2022 Permalink | Reply
    Tags:   

    Teaser 2846: Bingo! 

    From The Sunday Times, 9th April 2017 [link] [link]

    The infant teacher played a bingo game with his class. He had two identical dice, the numbers on the six faces of each being 1, 2, 2, 3, 3 and 3. He told the class that he would throw the pair of dice, add up the two numbers showing, and call that number out in a game of bingo. He then asked each member of the class to make their own bingo card consisting of five numbers of their own choice. He explained that they could use a number more than once on their card if they wished (and then delete just one occurrence of the number whenever it was called). Most of the class chose the five possible different totals as their bingo numbers, but one very clever girl chose the best possible selection.

    What were her five numbers?

    [teaser2846]

     
    • Jim Randell's avatar

      Jim Randell 9:51 am on 24 February 2022 Permalink | Reply

      When this puzzle was originally published it was suggested by several people on the Sunday Times Discussion Group that as 5 was the most likely outcome on each throw, then the best choice was (5, 5, 5, 5, 5). However, I wasn’t convinced.

      I considered a scenario where the class was sufficiently large that every possible bingo card was in play. In that case one of the cards would win after 5 throws of the dice, so we can generate all possible sequences of 5 throws and see which card is most likely to win.

      The card (5, 5, 5, 5, 5) can only win if every one of the throws is a 5, giving a (1/3)^5 = 1/243 = 0.4% chance. And there are 126 possible bingo cards, so there must be cards that have a better chance of winning.

      The following Python program examines all possible sequences of 5 throws, and it suggests a different answer for the best choice. It runs in 54ms.

      Run: [ @replit ]

      from enigma import (multiset, subsets, ordered, multiply, fdiv, printf)
      
      # n = number of throws
      n = 5
      
      # the scores on the die
      die = (1, 2, 2, 3, 3, 3)
      
      # find possible throws with a pair of dice
      throws = multiset.from_seq(a + b for (a, b) in subsets(die, size=2, select="M"))
      
      # consider each sequence of n throws
      r = multiset()
      for ns in subsets(sorted(throws.keys()), size=n, select="M"):
        r.add(ordered(*ns), count=multiply(throws[k] for k in ns))
      
      # output the 10 most common sequences
      best = r.most_common(10)
      N = pow(len(die), 2 * n)
      for (k, v) in best:
        printf("{k} -> {v} [{f:.1%}]", f=fdiv(v, N))
      printf()
      
      # output interesting patterns
      for k in [(5, 5, 5, 5, 5), (2, 3, 4, 5, 6), best[0][0]]:
        printf("{k} -> {v} [{f:.1%}]", v=r[k], f=fdiv(r[k], N))  
      

      In this scenario a choice of (5, 5, 5, 5, 5) is a poor choice (in 51st place), it would only be successful 0.4% of the time (as expected). A choice of (2, 3, 4, 5, 6) fares better at 0.9% (in 35th place). However the clear winner is a choice of (4, 4, 5, 5, 6) which wins 6.4% of the time.

      (I also ran 100 million random trials with 5 throws of the dice, and got results which matched the program above).

      Solution: Her five numbers were (4, 4, 5, 5, 6).


      Another way to analyse the problem is to consider each bingo card in isolation, and calculate the number of expected throws of the dice before it wins. (i.e. On average how many throws of the dice would it take).

      We can model the problem using an absorbing Markov chain [ @wikipedia ] which allows us to calculate the expected number of steps (i.e. throws of the dice), before being absorbed (i.e. completing the bingo card).

      The set of states are the stages of completion of the bingo card, and we can fill out the transition matrix with the probabilities of a transition between states at each throw of the dice. We can then manipulate the matrix to determine the expected number of steps between the transient states (partially completed bingo card) and the absorbing state (completed bingo card). And we want the number of steps from the initial transient state (i.e. the empty bingo card).

      This Python program calculates the expected number of sets for all 126 possible bingo cards, it runs in 177ms.

      Run: [ @replit ]

      from enigma import (Rational, multiset, subsets, irange, find, Matrix, unpack, printf)
      
      Q = Rational()
      
      # the values on a die
      die = (1, 2, 2, 3, 3, 3)
      
      # find distribution of possible throws
      throws = multiset.from_seq(a + b for (a, b) in subsets(die, size=2, select="M"))
      
      # denominator for throws
      td = throws.size()
      
      # calculate expected number of throws for target <tgt>
      def expected(tgt):
        # the states are subsets of the winning card
        m = multiset(tgt)
        ss = sorted(m.subsets(), key=(lambda x: (len(x), tuple(x))))
        ns = len(ss)
      
        # construct the transition matrix A = -P
        A = Matrix.create(ns, ns, 0, field=Q)
      
        # consider possible states
        for (i, src) in enumerate(ss):
          # and each throw
          for (x, p) in throws.items():
            # from src where does throw x get us?
            t = src.copy().add(x)
            j = find(ss, t)
            if j == -1: j = i
            A[i][j] -= Q(p, td)
      
        # convert to A = I - Q
        A.pop(-1)
        for (i, r) in enumerate(A):
          r[i] += 1
          r.pop(-1)
      
        # find the expected number of steps from each transient state
        E = A.linear_solve(1)
        # return expected number of steps from the initial state
        return E[0]
      
      
      # consider possible bingo cards with 5 numbers
      r = dict()
      for tgt in subsets(throws.keys(), size=5, select="R"):
        # find expected number of throws for this card
        r[tgt] = expected(tgt)
      
      # output lowest 10 expectation values
      for (i, (tgt, e)) in enumerate(sorted(r.items(), key=unpack(lambda t, e: e))):
        if i == 10: break
        printf("{tgt} -> {f:.3f}", f=float(e))
      printf()
      
      # output interesting patterns
      for k in [(5, 5, 5, 5, 5), (2, 3, 4, 5, 6), (4, 4, 5, 5, 6)]:
        printf("{k} -> {f:.3f}", v=r[k], f=float(r[k]))
      

      Using this measure (4, 4, 5, 5, 6) is again the winner, with 9.8 expected steps. (2, 3, 4, 5, 6) comes out at 38.2 steps (in 67th place), and (5, 5, 5, 5, 5) is 15.0 steps (in 28th position).

      (Again a simulation also gives matching results).


      Note that the ordering of “best” bingo cards differs depending on which measure you use, although the “best possible” card is the same in both scenarios.

      Here is a comparison of the top 10 bingo cards produced by the analyses above:


      In reality, the scenario is somewhere between these two approaches. It’s probably not the case that all 126 possible cards are in play (so the game might last longer than exactly 5 throws), but there is definitely more than 1 card in play (as most of the class chose (2, 3, 4, 5, 6)).

      If we know what cards are in play we can analyse the probability of one card winning before the others, as we have done before in puzzles that are variants on Penney’s game [ @wikipedia ]. (See: Enigma 630, Tantalizer 428, Enigma 287).

      Or we can use simulations to look at how a set of cards performs. I wrote code to play random trials for a group of cards until there is a winner.

      Playing A = (4, 4, 5, 5, 6) against B = (2, 3, 4, 5, 6) results in A winning 86.7% of the time, and B winning 15.9% of the time. (These add up to more than 100% because both cards can win on the final throw).

      Although playing C = (5, 5, 5, 5, 5) against B, shows that C is a better choice than B. With C winning 74.6% of the time, and B winning 25.4% of the time.

      Playing the top 3 performing cards from the analyses, (4, 4, 5, 5, 6), (4, 5, 5, 6, 6), (4, 5, 5, 5, 6), against (2, 3, 4, 5, 6) and (5, 5, 5, 5, 5) we get:

      (4, 4, 5, 5, 6) wins 47.5%
      (4, 5, 5, 6, 6) wins 42.9%
      (4, 5, 5, 5, 6) wins 25.0%
      (5, 5, 5, 5, 5) wins 10.5%
      (2, 3, 4, 5, 6) wins 10.1%

      Like

    • Jim Randell's avatar

      Jim Randell 4:11 pm on 22 September 2022 Permalink | Reply

      I found an article on the Royal Institution’s web site (or on an archive of it – [@archive.org]), where the setter of this puzzle is quoted:

      I wanted an interactive probability game to play with children. I wanted the game to reward good play i.e. a child who chose the best bingo card had a good chance of winning. I know from experience a lot of children (and adults, as evidenced by the response to the Sunday Times teaser!) choose all five numbers the same and choose the number that is most likely. In this case a lot of children opt for (5, 5, 5, 5, 5)  and the rest tend to opt for (2, 3, 4, 5, 6). Essentially I wanted a game where I could ask the winner ‘Why did you choose those numbers?’ and elicit an interesting response from the child that the rest of the group would find enlightening. The teaser printed by the Sunday Times was true except for the fact that the child in question was 9 years old.

      But he doesn’t reveal how either he or the 9-year-old arrived at the best solution.


      However, I did wonder if it is valid to construct an optimal card with (n + 1) numbers by adding a number to an optimal card with n numbers.

      Then using the “Win in n throws” method (rather than the Markov chains) we can quickly (and relatively easily) construct a card with 5 numbers (and also much larger cards).

      The code is as follows:

      Run: [ @replit ]

      from enigma import (multiset, subsets, append, Accumulator, arg, printf)
      
      # number of boxes on the card
      N = arg(5, 0, int)
      
      # the values on a die
      die = (1, 2, 2, 3, 3, 3)
      
      # find distribution of possible throws (with 2 dice)
      throws = multiset.from_seq(a + b for (a, b) in subsets(die, size=2, select="M"))
      
      # construct the best sequence for an <n> throw game
      (n, ts) = (0, multiset())
      while n < N:
        # find the best next throw
        r = Accumulator(fn=max)
        for (t, v) in throws.items():
          ts_ = append(ts, t)
          r.accumulate_data(v * ts_.multinomial(), ts_)
        (n, ts) = (n + 1, r.data)
        printf("{n} -> {ts}", ts=list(ts.sorted()))
      

      Using this program we find the best choice for bingo cards with 1 – 5 numbers are:

      1 → [5]
      2 → [4, 5]
      3 → [4, 5, 6]
      4 → [4, 5, 5, 6]
      5 → [4, 4, 5, 5, 6]

      As you would expect, for 1 number [5] is the best choice, as it is the most likely number to come up.

      But as soon as we move on to 2 numbers, we see that choosing another 5 is suboptimal.

      And this is because when 2 dice are thrown there is only one way to get [5, 5], and that is if each throw is a 5. The probability of this happening is (1/3)×(1/3) = 1/9 = 11.1%.

      But by choosing [4, 5] there are two ways this could be achieved – a 4 then a 5, or a 5 then a 4. And the probability of this happening is (5/18)×(1/3) + (1/3)×(5/18) = 5/27 = 18.5%.

      And so [4, 5] is better choice than [5, 5].

      Like

      • Jim Randell's avatar

        Jim Randell 4:45 pm on 20 October 2022 Permalink | Reply

        This puzzle was also published in Significance magazine (from The Royal Statistical Society) in the December 2021 issue [@link] (with the solution appearing in the February 2022 issue).

        I was able to get access to the online version of the magazine via my local library.

        Extract from Significance, February 2022, p8:

        The answer we were looking for is 4, 4, 5, 5, 6. We’ll hand over to reader Richard Jenkins to explain the solution.

        “Each time the dice are rolled, there are five possible outcomes (sums) with the following probabilities:

        P(sum is 2) = 1/36
        P(sum is 3) = 1/9
        P(sum is 4) = 5/18
        P(sum is 5) = 1/3
        P(sum is 6) = 1/4.

        Even though a sum of 5 has the highest probability on any single roll of the dice, it is very unlikely that a sum of 5 will be rolled each time when the dice are rolled multiple times. It is more likely that a variety of sums will appear”.

        This is an important point. Many readers wrote in to suggest a bingo card of 5, 5, 5, 5, 5. But, as Kyla E. Chasalow and Scott D. Chasalow explain in their submission – a detailed, eight-page tour de force of a solution – choosing all 5s “fails to take into account that bingo cards are unordered”. Roll the dice five times and there are 120 different roll sequences that will yield a win for the card 2, 3, 4, 5, 6. But there is only one way to win with a card of 5s.

        Back to Jenkins: “By reviewing the various combinations, we see there are 126 possible bingo cards (since the order of the numbers on the card does not matter). But which bingo card is the most likely to match all numbers in exactly five rolls? By crunching the numbers, I found that the combination of 4, 4, 5, 5, 6 has the highest probability of success”.

        Jenkins gives the four bingo cards with the highest probabilities of winning in five rolls as:

        P(4, 4, 5, 5, 6) = 0.064300412
        P(4, 5, 5, 6, 6) = 0.05787037
        P(3, 4, 5, 5, 6) = 0.051440329
        P(4, 5, 5, 5, 6) = 0.051440329

        Chasalow and Chasalow also identify 4, 4, 5, 5, 6 as the bingo card with the highest overall probability of winning in five rolls, explaining that: “This card reflects a trade-off between choosing high-probability outcomes and choosing different outcomes so that there are more ways to win”.

        — The Royal Statistical Society 2022

        Like

  • Unknown's avatar

    Jim Randell 11:26 am on 22 February 2022 Permalink | Reply
    Tags: by: Dr A Alan Taylor   

    Brain-Teaser 673: Crux numerorum 

    From The Sunday Times, 9th June 1974 [link]

    Professor Digby-Nite was excavating near Hadrian’s Wall last summer when he came across a clay tablet inscribed with this diagram and the words “CRUX NUMERORUM”.

    The clues when translated read:

    Across:
    I. Multiple of XXXVII.
    II. Multiple of LXXIII.
    III. A non-prime factor of I down.

    Down:
    I. A square.
    II. Multiple of VII.
    III. Calpurnia’s age.

    How old was Calpurnia?

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

    [teaser673]

     
    • Jim Randell's avatar

      Jim Randell 11:26 am on 22 February 2022 Permalink | Reply

      The grid is (of course) to be completed using Roman numerals.

      The following Python program runs in 50ms.

      Run: [ @replit ]

      from enigma import (int2roman, roman2int, irange, divisors, is_prime, catch, printf)
      
      # find length k romans
      def romans(ns, k=3):
        for n in ns:
          r = int2roman(n)
          if len(r) == k:
            yield r
      
      # multiples for i across
      n = roman2int('XXXVII')
      m1as = list(romans(irange(n, 5000, step=n)))
      
      # multiples for ii across
      n = roman2int('LXXIII')
      m2as = list(romans(irange(n, 5000, step=n)))
      
      # multiples for ii down
      n = roman2int('VII')
      m2ds = list(romans(irange(n, 5000, step=n)))
      
      # squares
      sqs = list(romans(i * i for i in irange(1, 70)))
      
      # i down (= ADG) is a square
      for (A, D, G) in sqs:
      
        # ii across is a multiple of 73
        for (D_, E, F) in m2as:
          if D_ != D: continue
      
          # i across is a multiple of 37
          for (A_, B, C) in m1as:
            if A_ != A: continue
      
            # ii down is a multiple of 7
            for (B_, E_, H) in m2ds:
              if B_ != B or E_ != E: continue
      
              # iii across is a non-prime factor of i down
              for (G_, H_, I) in romans(d for d in divisors(roman2int(A + D + G)) if not is_prime(d)):
                if G_ != G or H_ != H: continue
      
                # answer (must be valid roman)
                ans = catch(roman2int, C + F + I)
                if ans is None: continue
      
                # output solution
                printf("ans = {ans} [{A} {B} {C} / {D} {E} {F} / {G} {H} {I}]")
      

      Solution: Calpurnia is 19.

      The completed grid looks like this:

      Like

      • Jim Randell's avatar

        Jim Randell 1:54 pm on 22 February 2022 Permalink | Reply

        Manually:

        There is only one length 3 multiple of 73 (for II across):

        DXI = 511 = 7×73

        And there are only three length 3 squares (for I down):

        XVI = 16 = 4²
        XXV = 25 = 5²
        MDC = 1600 = 40²
        MMD = 2500 = 50²

        Of these, only MDC interlocks with DXI.

        There are only three length 3 multiple of 37 (for I across):

        CXI = 111 = 3×37
        DLV = 555 = 15×37
        MCX = 1110 = 30×37

        Of these, only MCX interlocks with MDC.

        Which leaves II down = “a multiple of VII” that matches “CX_”, it must be:

        CXL = 140 = 20×7

        And III across = “a non-prime divisor of 1600”, that matches “CL_”, it must be:

        CLX = 160 = 1600 / 10

        The grid is now complete and III down = XIX = 19.

        Like

  • Unknown's avatar

    Jim Randell 10:24 am on 20 February 2022 Permalink | Reply
    Tags: by: F. V. Rowden,   

    Brain-Teaser: Saturday’s child 

    From The Sunday Times, 22nd December 1957 [link]

    “How old are you, John?”, I asked my friend. He replied: “My father, his elder brother and I were all born in the summer, and we were all born on the same day of the week. Although our anniversaries are on different dates, this year they all fell on a Saturday”.

    “That’s very interesting”, I said, “but it isn’t very helpful, is it?”

    “It should be helpful”, said John, “because when I tell you that the years of our birth are all prime numbers there is no possible doubt about my age”.

    After argument, John convinced me he was right.

    How old are John, his father and his uncle?

    This one of the occasional Holiday Brain Teasers published in The Sunday Times prior to the start of numbered Teasers in 1961. A prize of £5 was offered.

    [teaser-1957-12-22] [teaser-unnumbered]

     
    • Jim Randell's avatar

      Jim Randell 10:25 am on 20 February 2022 Permalink | Reply

      The following Python program runs in 47ms.

      from datetime import (date, timedelta)
      from enigma import (defaultdict, primes, subsets, printf)
      
      # consider possible prime birth years
      years = set(primes.between(1835, 1956))
      
      # find Saturdays in the summer of 1957
      d = date(1957, 6, 1)
      while d.isoweekday() != 6:
        d += timedelta(days=1)
      
      r = defaultdict(set)
      while d.month < 9:
        # record previous years by day of the week
        for y in years:
          b = date(y, d.month, d.day)
          r[b.isoweekday()].add(y)
        d += timedelta(days=7)
      
      for (k, vs) in r.items():
        if len(vs) < 3: continue
      
        # select 3 birth years (Uncle, Father, John)
        for (U, F, J) in subsets(sorted(vs), size=3):
          # siblings are within 20 years
          if not (F - U < 21): continue
          # John's father is 18-40 years older than him
          if not (17 < J - F < 41): continue
          # output solution
          age = lambda x: 1957 - x
          printf("U = {U} ({u}); F={F} ({f}); J={J} ({j})", u=age(U), f=age(F), j=age(J))
      

      I found multiple solutions to this puzzle:

      John’s uncle was born in 1861. In 1957 he would be 96.
      John’s father was born in 1867 (6 years later). In 1957 he would be 90.
      John was born in 1889 (22 years later again). In 1957 he would be 68.

      John’s uncle was born in 1861. In 1957 he would be 96.
      John’s father was born in 1867 (6 years later). In 1957 he would be 90.
      John was born in 1901 (34 years later again). In 1957 he would be 56.

      John’s uncle was born in 1861. In 1957 he would be 96.
      John’s father was born in 1867 (6 years later). In 1957 he would be 90.
      John was born in 1907 (40 years later again). In 1957 he would be 50.

      John’s uncle was born in 1873. In 1957 he would be 84.
      John’s father was born in 1879 (6 years later). In 1957 he would be 78.
      John was born in 1913 (34 years later again). In 1957 he would be 44.

      The published solution is that John was 44, his father 78, and his uncle 84. Which is the last of the above solutions.

      If we assume that the actual dates of birth were not on Saturdays, then this is the only remaining solution. However I don’t think the puzzle text can be read to include this additional restriction. (In fact, the title of the puzzle, “Saturday’s child”, implies that they were all born on a Saturday, and so would exclude the final solution).

      This might account for comment given with the solution (5th January 1958):

      “More than 600 readers sent in their solution, but there was a fair proportion of erroneous answers.”

      Like

  • Unknown's avatar

    Jim Randell 4:10 pm on 18 February 2022 Permalink | Reply
    Tags:   

    Teaser 3100: Crate Expectations 

    From The Sunday Times, 20th February 2022 [link] [link]

    Pip and Estella know each other to be honest and clever. At the reading of Miss Havisham’s will they see a large crate on which are placed two envelopes addressed V+S+E and V, and a lipstick. The solicitor gives Estella the V+S+E envelope and Pip the V envelope and says, “Inside this crate Miss Havisham has left a cuboidal gold bar whose dimensions in mm are different whole numbers greater than 1, and whose volume, surface area and total edge length are V mm³, S mm² and E mm respectively. Inside your envelope, which you should now open, is the secret value of your address. Every fifteen minutes a bell will ring, and if at that point you know the other’s value, write both values on the crate with lipstick and the gold is yours”. At the first bell Pip and Estella sat still, but when the bell rang again Estella lipsticked 3177 and Pip’s value on the crate.

    What was Pip’s value?

    [teaser3100]

     
    • Jim Randell's avatar

      Jim Randell 4:49 pm on 18 February 2022 Permalink | Reply

      For a cuboid with dimensions x, y, z we have:

      V = xyz
      S = 2(xy + xz + yz)
      E = 4(x + y + z)

      V+S+E = xyz + 2(xy + xz + yz) + 4(x + y + z)
      V+S+E = (x + 2)(y + 2)(z + 2) – 8

      Estella knows that V+S+E = 3177, so we can find possible cuboids by looking at the decomposition of (3177 + 8) into three factors.

      But Pip did not respond at the first bell, so we can discard any cuboids that give a unique V+S+E value for the corresponding V value.

      I’ve added the [[ divisors_tuples() ]] function from Enigma 1062 to the enigma.py library.

      This Python program runs in 48ms.

      Run: [ @replit ]

      from enigma import (Record, divisors_tuples, printf)
      
      # determine cuboid values from (x, y, z) dimensions
      def cuboid(x, y, z):
        V = x * y * z
        S = 2 * (x * y + x * z + y * z)
        E = 4 * (x + y + z)
        return Record(x=x, y=y, z=z, V=V, S=S, E=E, VSE=V + S + E)
      
      # determine cuboid values from volume V
      def from_V(V):
        for (x, y, z) in divisors_tuples(V, 3):
          if 1 < x < y < z:
            yield cuboid(x, y, z)
      
      # determine cuboid values from V+S+E value
      def from_VSE(VSE):
        for (x, y, z) in divisors_tuples(VSE + 8, 3):
          if 3 < x < y < z:
            yield cuboid(x - 2, y - 2, z - 2)
      
      # Estella knows V+S+E = 3177
      for e in from_VSE(3177):
        # eliminate cuboids with volume V that have unique V+S+E values
        ps = set(p.VSE for p in from_V(e.V))
        if len(ps) < 2: continue
        # output solution
        printf("V={e.V} [x={e.x} y={e.y} z={e.z}] ps={ps}")
      

      Solution: Pip’s value was 1815.

      Given a V+S+E value of 3177, Estella knows the decomposition is one of:

      x=3, y=5, z=89; V=1335, S=1454, E=388; V+S+E = 3177
      x=3, y=11, z=47; V=1551, S=1382, E=244; V+S+E = 3177
      x=5, y=11, z=33; V=1815, S=1166, E=196; V+S+E = 3177

      Which means Pip has been given a value for V that is one of 1335, 1551, 1815.

      If Pip had been given 1335, he could work out:

      x=3, y=5, z=89; V=1335, S=1454, E=388; V+S+E = 3177

      If he had been given 1551, he could work out:

      x=3, y=11, z=47; V=1551, S=1382, E=244; V+S+E = 3177

      In either of these two cases Pip would have been able to declare both values at the first bell.

      He didn’t, so he must have been given 1815, which has the following decompositions:

      x=3, y=5, z=121; V=1815, S=1966, E=516; V+S+E = 4297
      x=3, y=11, z=55; V=1815, S=1606, E=276; V+S+E = 3697
      x=5, y=11, z=33; V=1815, S=1166, E=196; V+S+E = 3177

      There are multiple options, so Pip cannot declare at the first bell.

      Hence, of the three options, Estella knows Pip must have been given 1815 and can declare this at the next bell.

      Like

  • Unknown's avatar

    Jim Randell 8:55 am on 17 February 2022 Permalink | Reply
    Tags:   

    Teaser 2851: Knowing the lingo 

    From The Sunday Times, 14th May 2017 [link] [link]

    A group of 64 students can speak, between them, French, German and Russian. There are three times as many French speakers and two times as many German speakers as there are Russian speakers. The number who speak all three languages is one fifth of the number who speak French and at least one other of these languages. The number who speak all three languages is also two ninths of the number who speak German and at least one other of these languages. Furthermore, the number who speak all three languages is also two fifths of the number who speak Russian and at least one other of these languages.

    How many of the 64 students speak only French?

    [teaser2851]

     
    • Jim Randell's avatar

      Jim Randell 8:57 am on 17 February 2022 Permalink | Reply

      We assume that each of the students speaks at least one language (otherwise we can find many solutions), then we can represent the 7 internal areas of the Venn diagram: F, G, R, FG, FR, GR, FGR.

      So we have:

      F + G + R + FG + FR + GR + FGR = 64

      And the additional conditions give 5 more equations.

      But together these only give 6 equations in the 7 variables, so we need to choose a value for one of the regions to make a complete set of equations. The value for FGR region needs to be divisible by 2, so we can use that.

      The following Python program runs in 54ms.

      Run: [ @replit ]

      from enigma import (Matrix, as_int, irange, printf)
      
      # the given equations (incomplete)
      eqs = [
        #  F   G   R  FG  FR  GR FGR = k
        (( 1,  1,  1,  1,  1,  1,  1), 64), # 64 students in total
        ((-1,  0,  3, -1,  2,  3,  2),  0), # total F = 3(total R)
        (( 0, -1,  2, -1,  2,  1,  1),  0), # total G = 2(total R)
        (( 0,  0,  0, -1, -1,  0,  4),  0), # FGR = (1/5)(FG + FR + FGR)
        (( 0,  0,  0, -2,  0, -2,  7),  0), # FGR = (2/9)(FG + GR + FGR)
        (( 0,  0,  0,  0, -2, -2,  3),  0), # FGR = (2/5)(FR + GR + FGR)
      ]
      
      # choose a value for FGR
      for FGR in irange(0, 64, step=2):
        # make an additional equation for FGR
        #      F  G  R FG FR GR FGR = k
        eq = ((0, 0, 0, 0, 0, 0, 1), FGR)
      
        # solve the equations for non-negative integers
        try:
          vs = tuple(as_int(x, "0+") for x in Matrix.linear(eqs + [eq]))
        except ValueError:
          continue
      
        (F, G, R, FG, FR, GR, FGR) = vs
      
        # there must be at least 1 speaker of each language
        if R + FR + GR + FGR == 0: continue
      
        # output solution
        printf("F={F} G={G} R={R} FG={FG} FR={FR} GR={GR} FGR={FGR}")
      

      Solution: 25 of the students speak only French.

      There is only one possible arrangement (subject to the assumption above):

      F=25
      G=12
      R=5
      FG=12
      FR=4
      GR=2
      FGR=4


      We can manually simplify the equations:

      FGR = (1/5)(FG + FR + FGR) ⇒ 2 FG + 2 FR = 8 FGR
      FGR = (2/5)(FR + GR + FGR) ⇒ 2 FR + 2 GR = 3 FGR
      FGR = (2/9)(FG + GR + FGR) ⇒ 2 FG + 2 GR = 7 FGR
      ⇒ GR = FGR / 2
      ⇒ FR = FGR
      ⇒ FG = 3 FGR

      F + G + R + FG + FR + GR + FGR = N ⇒ F + G + R + (11/2) FGR = N
      F + FG + FR + FGR = 3(R + FR + GR + FGR) ⇒ F = 3 R + (5/2) FGR
      G + FG + GR + FGR = 2(R + FR + GR + FGR) ⇒ G = 2 R + (1/2) FGR
      ⇒ R = (N – (17/2) FGR) / 6
      ⇒ F = 3 R + (5/2) FGR
      ⇒ G = 2 R + (1/2) FGR

      So given an even value for FGR = 2k, we can calculate the values for the other regions:

      Run: [ @replit ]

      from enigma import (irange, div, printf)
      
      # total number of students
      N = 64
      
      # choose a value for FGR = 2k
      for k in irange(0, N // 2):
        n = N - 17 * k
        if n < 0: break
        R = div(n, 6)
        if R is None: continue
      
        # determine the other values
        FR = FGR = 2 * k
        GR = k
        FG = 3 * FGR
        F = 3 * R + 5 * k
        G = 2 * R + k
      
        # output solution
        printf("F={F} G={G} R={R} FG={FG} FR={FR} GR={GR} FGR={FGR}")
      

      If we do the steps manually we find we only need to check k = 0, 1, 2, 3, and only k = 2 gives viable values.

      Like

    • GeoffR's avatar

      GeoffR 11:45 am on 17 February 2022 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";
       
      var 1..30:F;  var 1..30:G;  var 1..30:R; 
      var 1..60:FG; var 1..60:FR; var 1..60:GR; 
      var 1..90:FGR; 
      
      % A group of 64 students can speak, between them, French, German and Russian
      constraint F + G + R + FG + FR + GR + FGR == 64;
      
      % There are 3X as many French speakers as there are Russian speakers
      constraint F + FG + FR + FGR == 3 * (R + FR + GR + FGR);
      
      % There are 2X as many German speakers as there are Russian speakers
      constraint G + FG + GR + FGR == 2 * (R + FR + GR + FGR);
      
      % Number who speak all three languages is one fifth of the number who speak
      % .. French and at least one other of these languages
      constraint 5 * FGR == FG + FR + FGR;
      
      % Number who speak all three languages is also two ninths of the number 
      % ..who speak German and at least one other of these languages
      constraint 9 * FGR == 2 *(FG + GR + FGR);
      
      % Number who speak all three languages is also two fifths of the number 
      % ..who speak Russian and at least one other of these languages
      constraint 5 * FGR == 2 *(FR + GR + FGR);
      
      solve satisfy;
      
      % F = 25;
      % G = 12;
      % R = 5;
      % FG = 12;
      % FR = 4;
      % GR = 2;
      % FGR = 4;
      % ----------
      % ==========
      
      
      

      Like

      • Jim Randell's avatar

        Jim Randell 4:24 pm on 17 February 2022 Permalink | Reply

        Although we are not told that each of the 7 subsets is non-empty (but we do know that there must be at least one student that speaks each of the languages).

        Like

    • GeoffR's avatar

      GeoffR 3:56 pm on 18 February 2022 Permalink | Reply

      Although the Solve Function is often used in Mathematica for solving sets of simultaneous equations, it did not work in this instance. It turns out that the FindInstance Function (ref Brian) was suitable. and can sometimes be used as an alternative solver in Mathematica.

      FindInstance[{ F + G + R + FG + FR + GR + FGR == 64,
        F + FG + FR + FGR == 3 (R + FR + GR + FGR),
        G + FG + GR + FGR == 2 (R + FR + GR + FGR),
        5 FGR == FG + FR + FGR,
        9 FGR == 2 (FG + GR + FGR),
        5 FGR == 2 (FR + GR + FGR),
        F + FG + FR + FGR > 0, G + FG + GR + FGR > 0,
        R + FR + GR + FGR > 0},
        {F, R, G, FG, FR, GR, FGR}, Integers ]
      
      {{F -> 25, R -> 5, G -> 12, FG -> 12, FR -> 4, GR -> 2, FGR -> 4}}
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 10:24 am on 15 February 2022 Permalink | Reply
    Tags:   

    Brain-Teaser 878: Four twos make …? 

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

    Two maths pupils had been indulging in the traditional “Four Fours” recreation, (i.e. seeing how many consecutive integers from 1 up they could express by means of a string of just four 4s with the signs for addition, subtraction, multiplication or division (to obviate numerator/denominator) interspersed as required, along with brackets where needed for clarity, but (according to their rules) featuring no power indices nor other aids except that each expression may use one decimal point. Examples illustrating all this are:

    18 = (4 / .4) + 4 + 4
    28 = 4 × (4 + 4) – 4

    As a variant they then tried working with 2s instead of 4s but soon found that there is a certain integer, lower than both of the above, which defeats every effort to express it with only four 2s. But when they used the minimum number of 2s to express it, they found, under corresponding conditions, that they could express it in a number of different ways. Indeed they found two ways which used neither addition nor multiplication.

    What were those two expressions?

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

    [teaser878]

     
    • Jim Randell's avatar

      Jim Randell 10:24 am on 15 February 2022 Permalink | Reply

      See also: Teaser 1949-12-25.

      We can take the code for Teaser 1949-12-25, and change it to using four 2’s, and only the 4 basic mathematical operators.

      We find that we can generate all the numbers from 1 to 16:

      1 = 22 / 22
      2 = (2 / 2) + (2 / 2)
      3 = 2 + 2 − (2 / 2)
      4 = 2 + 2 + 2 − 2
      5 = 2 + 2 + (2 / 2)
      6 = (2 + 2) × 2 − 2
      7 = 2 + 2 / (2 × .2)
      8 = 2 + 2 + 2 + 2
      9 = (22 / 2) − 2
      10 = 22 / 2.2
      11 = (2 / .2) + (2 / 2)
      12 = (22 + 2) / 2
      13 = (22 / 2) + 2
      14 = (2 / .2) + 2 + 2
      15 = (2 + (2 / 2)) / .2
      16 = (2 + 2) × (2 + 2)
      17 = ???

      So we can’t express 17 using four 2’s. But as we can express 15 using four 2’s that means we can certainly express 17 using five 2’s:

      17 = ((2 + (2 / 2)) / .2) + 2

      But the question asks us to express it without using addition or multiplication:

      17 = 22 − ((2 / 2) / .2)
      17 = 22 − ((2 / .2) / 2)

      Like

  • Unknown's avatar

    Jim Randell 10:05 pm on 13 February 2022 Permalink | Reply
    Tags:   

    Teaser 2739: Funny dice 

    From The Sunday Times, 22nd March 2015 [link] [link]

    I have two cube-shaped dice, one red and one blue, with a positive whole number on each face. When I throw the dice and add up the two numbers, the most likely total is 7. The next most likely totals are 6 and 8, the next are 5 and 9, the next are 4 and 10, the next are 3 and 11, and the least likely are 2 and 12. However, my dice are not standard: indeed, the total of the six numbers on the red dice is higher than the total of those on the blue dice.

    What are the six numbers on the red dice?

    [teaser2739]

     
    • Jim Randell's avatar

      Jim Randell 10:05 pm on 13 February 2022 Permalink | Reply

      See also: Teaser 3098, Enigma 382, Enigma 646b.

      We assume that the 6-sided dice are “fair” (i.e. when one is thrown each face has a 1/6 chance of showing), and also that each of the mentioned values (2-12) is an achievable throw with the pair.

      The probability of each combination must be expressible as n/36 and the sum of the probabilities must be 1.

      If we consider the lowest possible probabilities:

      2, 12 = 1/36
      3, 11 = 2/36
      4, 10 = 3/36
      5, 9 = 4/36
      6, 8 = 5/36
      7 = 6/36

      Then we find this accounts for 36/36, so must be the required distribution, and is the same distribution as a pair of standard dice.

      So the dice we are looking for are a non-standard pair with the same throw distribution as a standard pair.

      There is only one such value for 6-sided dice, known as the Sicherman dice.

      We can use the [[ sicherman() ]] function I wrote for Teaser 3098 to solve this problem.

      This Python program runs in 46ms (internal run time is 841µs).

      Run: [ @replit ]

      from enigma import printf
      from sicherman import sicherman
      
      for (d1, d2) in sicherman(6):
        if sum(d1) != sum(d2):
          printf("{d1} + {d2}")
      

      Solution: The numbers on the red die are: 1, 3, 4, 5, 6, 8.

      And the numbers on the blue die are: 1, 2, 2, 3, 3, 4.

      Like

    • Hugh+Casement's avatar

      Hugh+Casement 7:12 am on 14 February 2022 Permalink | Reply

      We are told ” the least likely are 2 and 12″ but there is no stipulation that they have to occur at all.
      I found eight sets where only sums from 3 to 11 can occur, with frequencies in the order given.
      So for me the puzzle is ill-defined — that’s apart from the misuse of the plural ‘dice’.

      Like

  • Unknown's avatar

    Jim Randell 3:07 pm on 11 February 2022 Permalink | Reply
    Tags:   

    Teaser 3099: Recurring theme 

    From The Sunday Times, 13th February 2022 [link] [link]

    Liam is learning about fractions and decimals. He has been shown that some fractions give rise to decimals with a recurring pattern eg 4/11 = 0.3636… . Each pupil in his class has been given four numbers. The largest (two-figure) number is to be used as the denominator and the others as numerators, to create three fractions that are to be expressed as decimals. Liam found that each decimal was of the form 0.abcabc…, with the same digits but in different orders.

    Liam’s largest number contained the digit 7 and if I told you how many of his four numbers were divisible by ten you should be able to work out the numbers.

    What, in increasing order, are the four numbers?

    [teaser3099]

     
    • Jim Randell's avatar

      Jim Randell 3:42 pm on 11 February 2022 Permalink | Reply

      We can use some handy routines from the enigma.py library to help in solving this puzzle. [[ recurring() ]] finds the recurring part of the decimal representation of a fraction, and [[ filter_unique() ]] can be used to find sets that are unique by the count of multiples of 10 involved.

      The following Python program runs in 91ms.

      Run: [ @replit ]

      from enigma import (defaultdict, irange, union, recurring, join, subsets, filter_unique, printf)
      
      # generate sets of possible numbers
      def generate():
        # choose the denominator (2-digits, one of them a 7)
        for d in union([irange(17, 97, step=10), irange(70, 79)]):
      
          # consider the smaller numbers, n/d = 0.(xyz)...
          # and record them by the digits that make up the repetend
          r = defaultdict(list)
          for n in irange(1, d - 1):
            (_, nr, rr) = recurring(n, d)
            if (not nr) and len(rr) == 3:
              r[join(sorted(rr))].append(n)
      
          # find sets of 3 numerators
          for ns in r.values():
            for ss in subsets(ns, size=3, fn=list):
              yield tuple(ss + [d])
      
      # find sets unique by the count of multiples of 10 involved
      fn = lambda ns: sum(n % 10 == 0 for n in ns)
      for ns in filter_unique(generate(), fn).unique:
        printf("{ns}")
      

      Solution: Liam’s numbers are: 4, 30, 40, 74.

      So we have:

      4/74 = 0.(054)…
      30/74 = 0.(405)…
      40/74 = 0.(540)…

      And this the only set of 4 numbers where 2 of them are divisible by 10.

      In all there are 30 possible sets of 4 numbers. 12 sets use a denominator of 37, and the numbers in these sets can be multiplied by 2 to give 12 further sets (that give the same fractions) using a denominator of 74. The remaining 6 sets have a denominator of 27.

      Of these there are 19 sets with none of the 4 numbers divisible by 10, and 10 sets with one of the 4 numbers divisible by 10. The remaining set has two of the numbers divisible by 10, and so gives the answer.

      Like

    • GeoffR's avatar

      GeoffR 3:09 pm on 15 February 2022 Permalink | Reply

      Not very elegant code, but it finds the answer, and runs in less than 100ms.
      I used two Python dictionaries in this solution.

      from enigma import recurring, join
      from collections import defaultdict
      
      # for potential number lists
      Nums = defaultdict(list)
      
      # for counting values in Nums divisible by 10
      D10 = defaultdict(list) 
      
      # using list of possible denominators including digit 7
      # .. to search for repeating decimal patterns
      for n in (17,27,37,47,57,67,70,71,72,73,74,75,76,77,78,79,87,97):
        (_, nr, rr) = recurring(1, n)
        if not(nr) and len(rr) == 3:
          print(f"Number = {n}, reciprocal = {1/n}")
      
      # only 27 and 37 were found as denominators with repeating patterns
      # ... add multiples 54 and 74 as extra 2-digit numbers
      # ...in search for all 3-digit repeating patterns
      for n in range(1, 80):
        for d in (27, 37, 54, 74):
          if n < d:
            (_, nr, rr) = recurring(n, d)
            if not(nr) and len(rr) == 3:
              Nums[join(sorted(rr)) + " " + str(d)].append(n)
      
      # add denominator (from the key) to values            
      for k, v in Nums.items():  
        v = v + [int(k[4:6])]
      
      # form a new dictionary D10, based on the Nums dict values
      # ... which are divisible by 10
      for k, v in Nums.items():
        tot10 = 0
        # count numbers divisible by 10
        for x in v:
          q, r = divmod(int(x), 10)
          if q and r == 0:
            tot10 += 1
          # add denominator to D10 values
          D10[tot10].append(v + [int(k[4:6])] )
      
      # look for a unique set of four numbers
      # ... based on the number of values divisible by 10
      for k, v in D10.items():
        if len(v) == 1:
          print(f"Four numbers are {v}")
      
      
      

      Like

    • A.T.Surherland's avatar

      A.T.Surherland 9:40 am on 16 February 2022 Permalink | Reply

      I have obtained an interesting answer :-
      The sum of the 3 lowest numbers = the greatest number.
      ie the sum of the fractions = 1.
      Is there a reason for this condition?.

      Like

      • Jim Randell's avatar

        Jim Randell 12:01 pm on 16 February 2022 Permalink | Reply

        There are 12 sets of numbers that work with a denominator of 37. Of these 6 have the fractions sum to 1, and 6 have the fractions sum to 2. And we can obviously multiply all the numbers up by a factor of 2 to get another 12 sets that behave the same.

        The remaining 6 sets of numbers (with denominator 27) give fractions that don’t sum to a whole number (but are all multiples of 1/9).

        This is presumably due to the 3 different digits in the repetends lining up, so that the repetend of the sum is a single digit, and in the case of .(9)… this gives a whole number.

        Like

      • Brian Gladman's avatar

        Brian Gladman 12:29 pm on 16 February 2022 Permalink | Reply

        If we add 0.abc… + 0.bca… + 0.cab… we will get 0.111… x (a + b + c) = (a + b + c) / 9, so sum(numerators) / denominator = (a + b + c) / 9. So this happens when a + b + c == 9, which it does in our case. The sum can be 2 when a + b + c equals 18 but it is not necessarily an integer.

        Like

    • GeoffR's avatar

      GeoffR 11:07 am on 16 February 2022 Permalink | Reply

      Yes, This is my understanding of the reason.

      A repeating fraction of the format 0.abcabcabc.. can be expressed exactly as a rational fraction abc/999 – see number theory elsewhere.

      Each of the three numerators in the answer divided by the denominator, gives a 3-digit repeating pattern.

      Without displaying the answer publicly, as this is a current Sunday Times Teaser,
      the three repeating fractions for this teaser can be expressed as:

      0.abcabcabc   0.cabcabcab   0.bcabcabca – since the three fractions use the same digits as a stated teaser condition.

      The rational fractions for this teaser are then abc/999, cab/999 and bca/999.

      Also, abc + cab + bca = 999.

      It can be seen that abc/999 + cab/999 + bca/999 = 1.

      Like

  • Unknown's avatar

    Jim Randell 9:10 am on 10 February 2022 Permalink | Reply
    Tags:   

    Teaser 2872: Appropriate arithmetic 

    From The Sunday Times, 8th October 2017 [link] [link]

    I wrote down three two-figure numbers, one of which was double one of the others. Overall the three numbers used six consecutive digits between them. I then added up the three numbers to give a three-figure sum, and I also multiplied together the three numbers to give a five-figure product. Replacing digits consistently by letters my two answers, appropriately, were ADD and TIMES.

    What were the three original numbers?

    [teaser2872]

     
    • Jim Randell's avatar

      Jim Randell 9:11 am on 10 February 2022 Permalink | Reply

      If we suppose the three numbers are ab, cd, ef, and that 2 × ab = cd then we have:

      ab + cd + ef = ADD
      ab × cd × ef = TIMES

      And we can use the [[ SubstitutedExpression ]] solver from the enigma.py library to solve the alphametic expressions.

      The following run file executes in 59ms (the generated program has an internal runtime of 575µs).

      Run: [ @replit ]

      #! python3 -m enigma -rr
      
      SubstitutedExpression
      
      --symbols="ADEIMSTabcdef"
      --distinct="ADEIMST,abcdef"
      --answer="(ab, cd, ef)"
      
      # cd is twice ab
      "2 * ab = cd"
      
      # sum is ADD, product is TIMES
      "ab + cd + ef = ADD"
      "ab * cd * ef = TIMES"
      
      # a, b, c, d, e, f are 6 consecutive digits
      --code="is_consecutive = lambda *vs: all(y == x + 1 for (x, y) in tuples(ordered(*vs), 2))"
      "is_consecutive({a}, {b}, {c}, {d}, {e}, {f})"
      
      # [optional]
      --template="(ab + cd + ef = ADD) (ab * cd * ef = TIMES)"
      --solution=""
      

      Solution: The three original numbers are: 23, 46, 75.

      Like

      • Frits's avatar

        Frits 1:17 pm on 10 February 2022 Permalink | Reply

        Instead of the all(…) condition you can also use:

        "(s := sorted([{a}, {b}, {c}, {d}, {e}, {f}]))[-1] - s[0] == 5"
        

        or

        "max(s := [{a}, {b}, {c}, {d}, {e}, {f}]) - min(s) == 5"
        

        Like

    • GeoffR's avatar

      GeoffR 3:07 pm on 10 February 2022 Permalink | Reply

      Using Frits second suggestion proved useful in a MiniZinc solution.

      
      % A Solution in MiniZinc
      include "globals.mzn";
      
      % Digits forming three 2-digit numbers ab, cd, ef
      var 1..9:a; var 1..9:b; var 1..9:c; 
      var 1..9:d; var 1..9:e; var 1..9:f;
      
      constraint all_different([a, b, c, d, e, f]);
      
      % The three 2-digit numbers used six consecutive digits between them
      constraint max([a,b,c,d,e,f]) - min([a,b,c,d,e,f]) == 5;
      
      var 10..99:ab == 10*a + b;
      var 10..99:cd == 10*c + d;
      var 10..99:ef == 10*e + f;
      
      constraint cd == 2 * ab; 
      
      % Upper case letters
      var 1..9:A; var 0..9:D; var 1..9:T; var 1..9:I;
      var 0..9:M; var 0..9:E; var 0..9:S;
      constraint all_different([A, D, T, I, M, E, S]);
      
      % Upper case sum and multiplication values
      var 100..999:ADD = 100*A + 11*D;
      var 10000..99999:TIMES = 10000*T + 1000*I + 100*M + 10*E + S;
      
      constraint ab + cd + ef == ADD;
      constraint ab * cd * ef == TIMES;
      
      solve satisfy;
      output ["The three original numbers were " ++ show([ab, cd, ef]) ];
      
      % The three original numbers were [23, 46, 75]
      % ----------
      % ==========
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 11:42 am on 8 February 2022 Permalink | Reply
    Tags: by: Margery Elliott   

    Brain-Teaser 902: Square telephones 

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

    “I have discovered”, said Ian, “that if I square my five-figure telephone number, the square ends in the same four figures, in the same order, as the number itself, which, incidentally, does not begin with a zero”.

    “Funnily enough”, said James, “the same things apply to my five-figure telephone number, which is different from Ian’s”.

    “There are quite a few numbers which fulfil that condition”, I said. “Give me some more information”.

    “If I were to tell you”, said Ian, “how many of the digits 1 to 9 do not appear in the square of my number, you could deduce the number”.

    “And you could deduce mine, if were to tell you how many of the digits 1 to 9 do not occur in the square of my number”, added James.

    “Then I already know enough to deduce your numbers”, I said, but I am not able to say whose is which”.

    My number is divisible by 29″, said James.

    This last statement enabled me to deduce Ian’s and James’s telephone numbers.

    What are they?

    [teaser902]

     
    • Jim Randell's avatar

      Jim Randell 11:47 am on 8 February 2022 Permalink | Reply

      This Python program runs in 60ms.

      Run: [ @replit ]

      from enigma import irange, sq, nsplit, filter_unique, printf
      
      # find possible 5-digit phone numbers (no leading 0)
      # whose square ends with the last 4 digits of the original number
      ps = list(n for n in irange(10000, 99999) if sq(n) % 10000 == n % 10000)
      
      # look for numbers which can be deduced from the number of unused
      # digits 1-9 in the square of the number
      digits = set(irange(1, 9))
      fn = lambda n: len(digits.difference(nsplit(sq(n))))
      ns = filter_unique(ps, fn).unique
      
      # from the candidates: divisible by 29 = James, else Ian
      for n in ns:
        x = ("James" if n % 29 == 0 else "Ian")
        printf("{x} = {n}")
      

      Solution: Ian’s number is 69376. James’ number is 60001.


      69376² = 4813029376, which doesn’t use 5 (i.e. 1 of the digits 1-9).

      60001² = 3600120001, which doesn’t use 4, 5, 7, 8, 9 (i.e. 5 of the digits 1-9).

      Like

    • GeoffR's avatar

      GeoffR 4:26 pm on 9 February 2022 Permalink | Reply

      @Jim:
      It looks as though James(not Ian’s) number should be 60001?

      “My number is divisible by 29″, said James.

      >>> divmod(69376,29) = (2392, 8) – Ian’s number must be 69376

      >>> divmod(60001,29) = (2069, 0) – James’ number must be 60001

      Like

    • GeoffR's avatar

      GeoffR 11:01 am on 11 February 2022 Permalink | Reply

      
      from enigma import irange, sq, nsplit
      from collections import defaultdict
      
      Nums = defaultdict(list)
      
      # re-using Jim's code list of  phone numbers 
      # find possible 5-digit phone numbers (no leading 0)
      # whose square ends with the last 4 digits of the original number
      ps = list(n for n in irange(10000, 99999) if sq(n) % 10000 == n % 10000)
       
      # digits 1-9 in the square of the number
      digits = set(irange(1, 9))
      
      # form a dictionary, indexing phone numbers by unused digits
      for p in ps:
        ud = len(digits.difference(nsplit(sq(p))))
        Nums[ud].append(p)
      
      # counter for single phone numbers in the dictionary
      cnt = 0
      for k, v in Nums.items():
        if len(v) == 1:
          cnt += 1
      
      # find the two phone numbers for James and Ian
      if cnt == 2:
        for k, v in Nums.items():
          if len(v) == 1:
            if v[0] % 29 != 0:
              print(f"Ian's phone number = {v[0]}")
            elif v[0] % 29 == 0:
              print(f"James' phone number = {v[0]}")
            
      # James' phone number = 60001
      # Ian's phone number = 69376
      
      

      Like

  • Unknown's avatar

    Jim Randell 4:15 pm on 4 February 2022 Permalink | Reply
    Tags:   

    Teaser 3098: Wonky dice 

    From The Sunday Times, 6th February 2022 [link] [link]

    I have two octahedral (eight-faced) dice. There are positive whole numbers (not necessarily all different) on each of their faces. I throw the two dice and add the two numbers that are showing on the top faces. The probability of a total of 2 is 1/64, the probability of a total of 3 is 2/64 and so on. The probabilities of the totals are the same as for a pair of standard octahedral dice (each numbered 1 to 8). Interestingly, however, the highest number on the first die is 11.

    What are the eight numbers (in ascending order) on the second die?

    [teaser3098]

     
    • Jim Randell's avatar

      Jim Randell 4:32 pm on 4 February 2022 Permalink | Reply

      (See also: Enigma 382, Enigma 646b).

      Using the routines I wrote for Enigma 382 we can find pairs of non-standard octahedral dice that score the same as a standard pair. (The octahedral equivalent of the Sicherman dice [@wikipedia]).

      It’s not quick though. The following Python program runs in 30s.

      from enigma import printf
      from dice import (throws, dice)
      
      # a standard pair of octahedral dice
      d = (1, 2, 3, 4, 5, 6, 7, 8)
      standard = throws(d, d)
      
      # find equivalent non-standard pairs 
      for (d1, d2) in dice(8, set(standard), s=1, k=0):
        if not (d1[-1] == 11 or d2[-1] == 11): continue
        if throws(d1, d2) == standard:
          printf("{d1} + {d2}")
      

      Solution: The numbers on the second die are: 1, 2, 2, 3, 3, 4, 4, 5.

      Without the stipulation that one of the dice has a score of 11 on it there are 3 non-standard pairs that give the same distribution of scores as a standard pair:

      (1, 2, 2, 3, 5, 6, 6, 7) + (1, 3, 3, 5, 5, 7, 7, 9)
      (1, 2, 3, 3, 4, 4, 5, 6) + (1, 2, 5, 5, 6, 6, 9, 10)
      (1, 2, 2, 3, 3, 4, 4, 5) + (1, 3, 5, 5, 7, 7, 9, 11)

      The solution is given by the final pair of dice.

      Like

      • Jim Randell's avatar

        Jim Randell 7:34 pm on 4 February 2022 Permalink | Reply

        With a bit of analysis we can get a much faster program.

        The only way to throw 2 is 1 + 1, and for the distribution to be the same as a standard dice, there can only be one 1 on each die.

        One die has an 11 on it, which means the maximum possible for the other die is 5. (And there can only be one each of these).

        So the dice are:

        (1, (2-10)×6, 11) + (1, (2-4)×6, 5)

        Limiting the dice considered to just these possibilities gives a faster program.

        The following Python program runs in 98ms.

        Run: [ @replit ]

        from enigma import (irange, multiset, printf)
        
        # generate possible throws from a pair of dice
        def throws(d1, d2, fn=multiset, op=lambda a, b: a + b):
          return fn(op(a, b) for a in d1 for b in d2)
        
        # a standard pair of octahedral dice
        d = (1, 2, 3, 4, 5, 6, 7, 8)
        standard = throws(d, d)
        
        # add faces to dice d1 and d2
        # n = number of faces on each die
        # d1 = dice 1 (so far)
        # d1_min, d1_max = min/max values for d1
        # d2 = dice 2 (so far)
        # d2_min, d2_max = min/max values for d2
        # ts = target throws
        def solve(n, d1, d1_min, d1_max, d2, d2_min, d2_max, ts):
          if d1.size() == 8:
            if d2.size() == 8:
              # check throws
              if throws(d2, d1) == ts:
                yield (d2, d1)
            else:
              # swap dice over
              yield from solve(n, d2, d2_min, d2_max, d1, d1_min, d1_max, ts)
          else:
            # add face to d1
            for x in irange(d1_min, d1_max):
              d1_ = d1.copy().add(x)
              if throws(d1_, d2).issubset(ts):
                yield from solve(n, d1_, x, d1_max, d2, d2_min, d2_max, ts)
            
        # find equivalent non-standard pairs
        d1 = multiset.from_seq([1, 5])
        d2 = multiset.from_seq([1, 11])
        for (d1, d2) in solve(8, d1, 2, 4, d2, 2, 10, standard):
          printf("{d1} + {d2}", d1=sorted(d1), d2=sorted(d2))
        

        Like

        • Frits's avatar

          Frits 5:43 pm on 10 July 2023 Permalink | Reply

          @Jim,

          Unfortunately your variable d1_min is fixed. If you could set d1_min to the second highest value (with a minimum of 2) the program would be more efficient. A similar change to a recursive program on PuzzlingInPython [https://brg.me.uk/?p=7660#comment-3853] resulted in a 9 times faster program.

          Like

      • Jim Randell's avatar

        Jim Randell 10:47 am on 5 February 2022 Permalink | Reply

        The Mathematical justification section on the Wikipedia page for Sicherman dice [link], shows how to construct the factorisation of the generating polynomial for an n-sided standard die using cyclotomic polynomials [link].

        We can then look at non-standard ways to combine these factors into pairs of polynomials, such that each polynomial represents a valid 8-sided die, and their product represents the throws of a standard pair of dice. And we are interested in the case where the largest number on one of those dice is 11.

        Here is a routine that generates the nth cyclotomic polynomial, using the [[ Polynomial ]] class from the enigma.py library. (Although for this puzzle it is sufficient to find the cyclotomic polynomials for n = 2, 4, 8, which are all powers of a prime, and so easily determined).

        from enigma import (Polynomial, prime_factor, multiples, irange)
        
        # return the nth cyclotomic polynomial (can be @cached)
        def cyclotomic(n):
          if n < 1: return None
          if n == 1: return Polynomial([-1, 1]) # x - 1
          fs = list(prime_factor(n))
          if len(fs) == 1:
            (p, e) = fs[0]
            if e == 1: return Polynomial([1] * n) # prime
            # power of a prime
            q = n // p
            return Polynomial.from_pairs((k * q, 1) for k in irange(0, p - 1))
          else:
            p = Polynomial.from_pairs([(0, -1), (n, 1)]) # x^n - 1
            for d in multiples(fs):
              if d < n:
                (p, r) = p.divmod(cyclotomic(d))
            return p
        

        We can then use this to write a routine that generates pairs of dice that have the same distribution of throws as a pair of standard dice. (For 6-sided dice, the non-standard pair is known as the Sicherman dice):

        from enigma import (Polynomial, multiset, divisors, subsets, printf)
        
        # find pairs of n-sided dice with the same distribution as a standard pair
        def sicherman(n):
        
          # polynomial p(x) = x must be present on all dice
          x = Polynomial([0, 1])
        
          # make a die from a collection of polynomial (factor, multiplicity) pairs
          def die(ps):
            fs = multiset.from_pairs(ps)
            p = x * Polynomial.multiply(fs)
            if sum(p) == n and all(c >= 0 for c in p):
              return tuple(sorted(multiset.from_pairs(p.to_pairs())))
        
          # find the remaining factors of the generating polynomial of a standard die
          fs = list(cyclotomic(d) for d in divisors(n) if d > 1)
        
          # choose 0, 1, 2 copies of each factor
          for ms in subsets((0, 1, 2), size=len(fs), select="M"):
            # make the first die
            d1 = die(zip(fs, ms))
            if d1:
              # make the second die
              d2 = die((f, 2 - m) for (f, m) in zip(fs, ms))
              if d2 and not (d1 > d2):
                # return the pair
                yield (d1, d2)
        

        And finally we can solve the puzzle, by looking for a pair of 8-sided dice, with the same throw distribution as a pair of standard dice, but where one of the dice has a largest value of 11.

        This Python program runs in 47ms (internal run time is just 883µs).

        Run: [ @replit ]

        # solve the puzzle
        for (d1, d2) in sicherman(8):
          if d1[-1] == 11 or d2[-1] == 11:
            printf("{d1} + {d2}")
        

        Like

      • Frits's avatar

        Frits 11:53 am on 10 July 2023 Permalink | Reply

        @Jim,

        Where can I find your dice package (except as separate functions in Enigma 382) ?

        Like

    • A.T.Surherland's avatar

      A.T.Surherland 9:34 am on 16 February 2022 Permalink | Reply

      Refer to a paper by Duane M Bourne,Auburn University,Auburn on the above subject.
      This paper lists the octahedral answer plus other configurations..

      Like

    • Frits's avatar

      Frits 12:45 pm on 13 July 2023 Permalink | Reply

      Jim mentioned 3 non-standard pairs that give the same distribution of scores as a standard pair. These have symmetrical properties. The (1, 8) ,(2,7), (3,6) and (4,5) positional numbers of dice 1 and 2 all add up to 18.

      The following program tries to limit unnecessary work by controlling the range of each number on a die.

       
      from itertools import product
      
      # check die (1, (2-10)×6, 11) + (1, (2-4)×6, 5) 
      
      # chances            2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
      # for standard dice  1, 2, 3, 4, 5, 6, 7, 8,  7,  6 , 5,  4,  3,  2 , 1
      N, E1 = 8, 11
      E2 = 2 * N - E1
      
      # chance dictionary
      d = {i: N - abs(i - N - 1) for i in range(2, 2 * N + 1)}
      
      # check for standard chance distribution
      def check(s1, s2):
        cd = [0] * (2 * N + 1)
        for m in s1:
          for n in s2:
            if cd[(mn := m + n)] >= d[mn]:
              return False
            cd[mn] += 1
        return True     
      
      # minima range ([2, 2, 3, 3, 3, 4])  
      mn1 = sum([[i] * i for i in range(2, 5)], [])[:N - 2]
      mn2 = sum([[i] * i for i in range(2, 5)], [])[:N - 2]
      # maxima range ([8, 9, 9, 9, 10, 10] and [2, 3, 3, 3, 4, 4])
      mx1 = sum([[i] * (E1 - i + 1) for i in range(E1 - 3, E1)], [])[2 - N:]
      mx2 = sum([[i] * (E2 - i + 1) for i in range(E2 - 3, E2)], [])[2 - N:]
      
      # try to further lower the maxima for 1st die
      # total sum of numbers on both dice is 2 * tri(N)
      # minimal sum of 2nd die is 1 + E2 + sum(mn2) = 23
      # maximal value of 2nd digit is (N * (N + 1) - 23 - 1 - E1) / 6 = 6.17
      # maximal value of 3rd digit is (N * (N + 1) - 23 - 12 - 2) / 5 = 7
      # maximal value of 4th digit is (N * (N + 1) - 23 - 12 - 2 - 2) / 4 = 8.x
      # maximal value of 5th digit is (N * (N + 1) - 23 - 12 - 2 - 2 - 3) / 3 = 10
      mx = N * (N + 1) - (sum(mn2) + 1 + E2 + 1 + E1) 
      mx1 = [min((mx - sum(mn2[:i])) // (N - 2 - i), mx1[i]) for i in range(6)]
      
      # die 1: [A, B, C, D, E, F, H]
      A, H = 1, E1
      # product can be used instead of 6 separate loops as 2nd die ranges are compact
      # (and don't allow for decreasing variables)
      for n6 in product(*[range(mn2[i], mx2[i] + 1) for i in range(6)]):
        die2 = (1, ) + n6 + (E2, )
        sum2 = sum(die2)
        # skip if B gets too high (total numbers on dice will exceed N * (N + 1))
        m = (rB := N * (N + 1) - sum([A, H]) - sum2) // 6
        for B in range(mn1[0], min(m, mx1[0]) + 1):
          if not check([A, B, H], die2): continue
          for C in range(B, min((rC := rB - B) // 5, mx1[1]) + 1):
            if not check([A, B, C, H], die2): continue
            for D in range(max(mn1[2], C), min((rD := rC - C) // 4, mx1[2]) + 1):
              if not check([A, B, C, D, H], die2): continue
              for E in range(max(mn1[3], D), min((rD - D) // 3, mx1[3]) + 1):
                if not check([A, B, C, D, E, H], die2): continue
                for F in range(E, mx1[4] + 1):
                  G = N * (N + 1) - sum([A, B, C, D, E, F, H]) - sum2
                  if not F <= G < H: continue
                  if not check([A, B, C, D, E, F, G, H], die2): continue
                  print("answer:", sorted(die2))  
      

      Like

  • Unknown's avatar

    Jim Randell 10:45 am on 3 February 2022 Permalink | Reply
    Tags:   

    Teaser 2861: Fond memories 

    From The Sunday Times, 23rd July 2017 [link] [link]

    One of my memories of my grandparents’ house is of an ornament consisting of three monkeys with the caption “See no evil, hear no evil, speak no evil”.

    I have written down four odd numbers, one of them being the sum of the other three. Then I have consistently replaced digits with letters, using different letters for different digits. In this way the four numbers have become:

    SPEAK
    HEAR
    SEE
    EVIL

    What number is represented by SPEAK?

    [teaser2861]

     
    • Jim Randell's avatar

      Jim Randell 10:47 am on 3 February 2022 Permalink | Reply

      E, K, L, R must be odd digits, and SPEAK must be the result of the sum.

      We can use the [[ SubstitutedExpression ]] solver from the enigma.py library to solve the puzzle.

      The following run file executes in 128ms.

      Run: [ @replit ]

      #! python3 -m enigma -rr
      
      SubstitutedExpression
      
      # the alphametic sum
      "SEE + HEAR + EVIL = SPEAK"
      
      # the numbers are all odd, so E, K, L, R are odd digits
      "E % 2 = 1"
      "R % 2 = 1"
      "L % 2 = 1"
      "K % 2 = 1"
      
      --answer="SPEAK"
      

      Solution: SPEAK = 12507.

      There are 2 ways to arrive at the solution:

      155 + 6503 + 5849 = 12507
      155 + 6509 + 5843 = 12507

      The values of L and R can be swapped. They are 3 and 9 (in some order).

      Like

    • GeoffR's avatar

      GeoffR 8:35 pm on 3 February 2022 Permalink | Reply

      
      % A Solution in MiniZinc
      include "globals.mzn";
      
      var 1..9:S; var 0..9:P; var 1..9:E;  var 0..9:A;  var 0..9:K;
      var 1..9:H; var 0..9:R; var 0..9:V;  var 0..9:I;  var 0..9:L;
      
      constraint all_different ([S,P,E,A,K,H,R,V,I,L]);
      
      var 10000..99999: SPEAK == 10000*S + 1000*P + 100*E + 10*A + K;
      var 1000..9999: HEAR == 1000*H + 100*E + 10*A + R;
      var 1000..9999: EVIL == 1000*E + 100*V + 10*I + L;
      var 100..999: SEE == 100*S + 11*E;
      
      constraint SPEAK == HEAR + SEE + EVIL;
      
      % Confirm four numbers are odd
      constraint SPEAK mod 2 == 1 /\ HEAR mod 2 == 1
      /\ SEE mod 2 == 1 /\ EVIL mod 2 == 1;
      
      solve satisfy;
      
      output ["HEAR = " ++ show(HEAR) ++ ", SEE = " ++ show(SEE) ++ 
      ", EVIL = " ++ show(EVIL) ++ ", SPEAK = " ++ show(SPEAK)];
      
      % HEAR = 6509, SEE = 155, EVIL = 5843, SPEAK = 12507
      % ----------
      % HEAR = 6503, SEE = 155, EVIL = 5849, SPEAK = 12507
      % ----------
      % ==========
      
      

      Like

  • Unknown's avatar

    Jim Randell 8:54 am on 1 February 2022 Permalink | Reply
    Tags:   

    Brain-Teaser 652: Stumped! 

    From The Sunday Times, 6th January 1974 [link] [link]

    The scoreboard at our local cricket ground shows the total number of runs scored, the number of wickets fallen and the scores of the two batsmen in at the time.

    At the match last Sunday we declared at 500 for 8 wickets, when our first man in had just reached 100 runs (I was the other opener and was already out for 20). The seventh batsman had also scored a century, and there were no ‘extras’ at all in the match (i.e. all the runs were scored by the batsmen).

    Some time after my dismissal I noticed that the scoreboard showed eight similar digits (e.g. 999 for 9, both men in having scored 99 each) and later the board showed eight consecutive digits in ascending order, though with 0 following 9 (e.g. 678 for 9; batsmen with 01 and 23).

    What were the two scores I had seen?

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

    [teaser652]

     
    • Jim Randell's avatar

      Jim Randell 8:56 am on 1 February 2022 Permalink | Reply

      The innings was declared 500 for 8, so the options are:

      For scores greater between 20 and 500 we have:

      444 for 4, (44 and 44)
      333 for 3, (33 and 33)
      222 for 2, (22 and 22)
      111 for 1, (11 and 11)

      The last of these is not possible. If only one batsman has been dismissed, it is the setter for 20, so the total score would be 20 + 11 + 11 = 42, not 111.

      The second time the scoreboard could be showing (assuming the “in” scores can have a leading zero):

      456 for 7, (89 and 01)
      345 for 6, (78 and 90)
      234 for 5, (67 and 89)
      123 for 4, (56 and 78)

      Again the last of these is not possible, as the sum of the scores of the “in” batsmen is more than the total score.

      So we have the following potential observations:

      444 → 456
      333 → 345, 456
      222 → 234, 345, 456

      But some of these transitions are not possible.

      222 → 234 – only 12 more runs have been scored but the “in” scores have increased by 45 and 67 = 112
      222 → 345 – only 123 more runs have been scored, but the “in” scores have increased by 56 and 68 = 124
      333 → 345 – only 12 more runs have been scored, but the “in” scores have increased by 45 and 57 = 102
      444 → 456 – only 12 more runs have been scored, but one of the “in” scores has increased by 45

      Which leaves only the following transitions:

      333 → 456
      222 → 456

      Consider the “333 for 3” → “456 for 7” transition:

      Initially the score is “333 for 3”, and the “in” batsmen have both scored 33. So the 3 dismissed batsmen must have scored 267 between them. We know one of these is the setter, who scored 20. Which leaves 247 to be scored between the remaining 2 dismissed batsmen. We’ll distribute the runs as 123 and 124 run to batsmen 3 and 4:

      1: 33 (not out)
      2: 20 (out, setter)
      3: 123 (out)
      4: 124 (out)
      5: 33 (not out)

      By the time we get to “456 for 7”, the first batsman must have increased his score to 89, and the remaining “in” batsman has a score of 1 (let’s say this is batsman 9):

      1: 89 (not out)
      2: 20 (out, setter)
      3: 123 (out)
      4: 124 (out)
      5: ≥ 33 (out)
      6: ? (out)
      7: ≥100 (out)
      8: ? (out)
      9: 1 (not out)

      But these already sum to 490, which is more than 456, so this situation is not possible.

      Consider the “222 for 2” → “456 for 7” transition:

      Initially the score is “222 for 2”, and the “in” batsmen have both scored 22. So the 2 dismissed batsmen must have scored 178 between them, and we know one of them is the setter, who scored 20. So the other must have scored 158 (let’s say that was the 3rd batsman):

      1: 22 (not out)
      2: 20 (out, setter)
      3: 158 (out)
      4: 22 (not out)

      By the time we get to “456 for 7” the 1st batsman must have increased his score to 89, and the remaining “in” batsman has a score of 1 (let’s say this is batsman 9):

      1: 89 (not out)
      2: 20 (out, setter)
      3: 158 (out)
      4: ≥22 (out)
      5: ? (out)
      6: ? (out)
      7: ≥100 (out)
      8: ? (out)
      9: 1 (not out)

      This leaves 66 runs to distribute between 4, 5, 6, 7, 8. Which is possible.

      So this is the only possible situation.

      Solution: The two scores are: “222 for 2, (22 and 22)” and: “456 for 7, (89 and 01)”.

      Like

  • Unknown's avatar

    Jim Randell 9:57 am on 30 January 2022 Permalink | Reply
    Tags: by: Mr. Alwyn Hazel   

    Brain Teaser: Four fours 

    From The Sunday Times, 25th December 1949 [link]

    Many readers will recall the problem of constructing the integers each by means of four fours, with the usual mathematical signs. For example:

    17 = (4×4) + 4/4
    71 = (4! + 4.4)/.4

    Competitors are invited to submit a continuous series of integers so constructed, beginning with 1 and proceeding, without gaps, as far as possible.

    A follow-up was posted on 1st January 1950, to elaborate on the allowed constructions (although it is not as explicit as it could have been): [link]

    The problem set was that of constructing a continuous series of integers each by means of four fours, “with the usual mathematical signs”. Several readers have asked for a closer definition of the phrase quoted.

    It covers all signs (not themselves letters or numbers other than 4) which “every schoolboy knows”. It therefore includes: addition, subtraction, multiplication and division signs, square roots (and fourth roots), fourth powers, factorial signs, decimal points and recurring points, and combinations of these. It does not include gamma functions, logs or anti-logs, permutations or combinations, or trigonometrical functions. Nor does it include (as some hopeful readers have permitted themselves to believe) the use of square brackets to indicate “the integral part of”.

    This one of the occasional Holiday Brain Teasers published in The Sunday Times prior to the start of numbered Teasers in 1961. A prize of 5 guineas was offered for the longest list.

    [teaser-1949-12-25] [teaser-unnumbered]

     
    • Jim Randell's avatar

      Jim Randell 9:59 am on 30 January 2022 Permalink | Reply

      This is a puzzle that has appeared with many variations, see [ @wikipedia ].

      I limited my program to dealing with rational calculations where both the numerator and denominator are less than 1,000,000,000,000.

      Using the five 2-argument operators +, −, ×, ÷, ^, along with 1-argument functions sqrt(x) and fact(n), I found it was possible to construct the integers from 0 to 112.

      But then we reach an impasse at 113 (and: 157, 158, 161, 163, 166, 167, 171, 173, 185, 187, 191, 193, 197, 199, …).

      So it would be reasonable to suppose that a list of constructions from 1 to 112 would provide the required solution.

      However, in the solution published in The Sunday Times [ link ] a possible construction for 113 is given:

      113\; =\; \frac{4!}{.\dot{\left( \sqrt{4} \right)}}\; +\; \frac{\sqrt{4}}{.4}

      In which the literal construction .(123)… is turned into an operator.

      The first denominator is interpreted as:

      .(√4)… = .(2)… = 2/9

      giving:

      (4! / .(√4)…) + (√4 / .4)
      = 24/(2/9) + 2/(4/10)
      = 108 + 5
      = 113

      And 157 is apparently constructed as:

      157 = \frac{\sqrt{.\dot{4}}\; + \left( .4\; -\;  .\left( .\sqrt{4} \right) \right)}{.\left( .\sqrt{.\dot{4}}\right)}

      which I don’t understand. (Although it is possible I have mis-transcribed it from the image in The Sunday Times digital archive).

      A prize was awarded for construction of numbers in this fashion up to 1041.

      But if we can co-opt the construction of recurring decimals, why not co-opt the literal concatenation operation (on integers) so:

      12 : 3 = 123

      In that way 113 can be constructed as follows:

      ((√4 : 4!) + √4) / √4
      = ((2 : 24) + 2) / 2
      = (224 + 2) / 2
      = 226 / 2
      = 113

      But it doesn’t help with 157.

      Alternatively if sq(x) is allowed as the square of a number (the inverse of sqrt(x)) we can have:

      sq(4) + sq(4) + sq(4 / .(4)…)
      = 16 + 16 + sq(4/(4/9))
      = 32 + sq(9)
      = 32 + 81
      = 113

      (sq(fact(4)) + sq(44)) / sq(4)
      = (sq(24) + 1936) / 16
      = (576 + 1936) / 16
      = 2512 / 16
      = 157

      But allowing sq(x) only gets us to 306.

      Another alternative (which is sanctioned by the published solution, even though it was not explicitly mentioned in the clarification) is to allow the tri(n) function which gives the nth triangular number (as an analogy to fact(n) giving the n factorial):

      fact(n) = 1 × 2 × … × n
      tri(n) = 1 + 2 + … + n

      This allows us to construct 113 and 157:

      tri(4) × tri(4) + tri(4) + tri(√4)
      = 10 × 10 + 10 + 3
      = 113

      tri(4) × tri(4) + tri(tri(4)) + √4
      = 10 × 10 + tri(10) + 2
      = 100 + 55 + 2
      = 157

      And using tri(n) lets us get all the way to 3526. (I did not find constructions for 3527, 3707, 3947, 3989, 5164).

      A prize was also awarded to a list (using tri()) up to 2338.

      I used the following operations:

      + (addition)
      − (subtraction)
      × (multiplication)
      ÷ (division)
      ^ (general powers, not just fourth powers)
      sqrt(x) (square root (rational))
      fact(x) (factorial (integer))
      tri(x) (triangular numbers (integer))

      I didn’t implement fourth roots (which presumably use up one of the 4 digits), or general roots, as they didn’t seem to be useful when I experimented with them, and I didn’t allow the co-opting of literal construction methods.

      Using these operators I got:

      0 = 44 − 44
      1 = 44 / 44

      1041 = tri(44) + tri(tri(4)) − 4
      1042 = tri(44) + tri(tri(4)) − tri(√4)

      2338 = tri(4) + tri(4 × fact(4)) / √4
      2339 = tri(4) + tri(tri(4 × 4)) / 4

      3526 = tri(tri(4)) × (4 ^ tri(√4)) + fact(tri(√4))
      3527 = ???

      And it turns out we can manage all of these without needing to use the recurring literals at all (if we are allowing tri()).


      The following program produces constructions (without using tri()) for values up to 112. Although it displays the first construction found for each number, which is not necessarily the most aesthetically pleasing construction.

      It runs in 2.4s, and can be adapted to include tri() (and to remove recurring literals) to give constructions for numbers up to 3526 (in a few minutes).

      Run: [ @replit ]

      from enigma import (Rational, irange, product, is_square, factorial, tri, sprintf as f, number, arg, printf)
      
      Q = Rational()
      
      # possible literals using 1 - 4 digits
      # <number of 4's used> -> { (<value> -> <repr>, ... }
      lits = {
        1: {
          Q(4, 1): "4",
          Q(4, 10): ".4",
          Q(4, 9): ".(4)...",
        },
        2: {
          Q(44, 1): "44",
          Q(44, 10): "4.4",
          Q(44, 100): ".44",
          Q(40, 9): "4.(4)...",
          Q(4, 9): ".4(4)...",
        },
        3: {
          Q(444, 1): "444",
          Q(444, 10): "44.4",
          Q(444, 100): "4.44",
          Q(444, 1000): ".444",
          Q(400, 9): "44.(4)...",
          Q(40, 9): "4.4(4)...",
          Q(4, 9): ".44(4)...",
        },
        4: {
          Q(4444, 1): "4444",
          Q(4444, 10): "444.4",
          Q(4444, 100): "44.4",
          Q(4444, 1000): "4.444",
          Q(4444, 10000): ".4444",
          Q(4000, 9): "444.(4)...",
          Q(400, 9): "44.4(4)...",
          Q(40, 9): "4.44(4)...",
          Q(4, 9): ".444(4)...",
        }
      }
      
      M = number("1_000_000_000_000")
      def check(v): return (v if v.denominator < M and -M < v.numerator < M else None)
      
      def add(a, b): return (check(a[0] + b[0]), f("({a[1]}) + ({b[1]})"))
      def sub(a, b): return (check(a[0] - b[0]), f("({a[1]}) - ({b[1]})"))
      def mul(a, b): return (check(a[0] * b[0]), f("({a[1]}) * ({b[1]})"))
      def div(a, b): return (check(a[0] / b[0]), f("({a[1]}) / ({b[1]})"))
      
      def sqrt_(a):
        (v, r) = a
        p = is_square(v.numerator)
        if p is not None:
          q = is_square(v.denominator)
          if q is not None:
            return (Q(p, q), f("sqrt({r})"))
        return (None, None)
      
      def fact_(a):
        (v, r) = a
        if v.denominator == 1 and 0 <= v.numerator < 100:
          x = factorial(v.numerator)
          if x < M:
            return (Q(x, 1), f("fact({r})"))
        return (None, None)
      
      def pow_(a, b):
        if b[0].denominator == 1 and 0 <= b[0].numerator <= 10:
          x = a[0] ** b[0].numerator
          if x < M:
            return (Q(x, 1), f("({a[1]}) ^ ({b[1]})"))
        return (None, None)
      
      def tri_(a):
        (v, r) = a
        if v.denominator == 1 and v.numerator >= 0:
          x = tri(v.numerator)
          if x < M:
            return (Q(x, 1), f("tri({r})"))
        return (None, None)
      
      # operators
      ops = {
        # unary
        1: {
          'sqrt': sqrt_,
          'fact': fact_,
          #'tri': tri_,
        },
        # binary
        2: {
          'add': add,
          'sub': sub,
          'mul': mul,
          'div': div,
          'pow': pow_,
        },
      }
      
      # values to skip
      skip = set()
      
      
      # values to skip
      skip = set()
      skip.update({113, 157, 158, 161, 163, 166, 167, 171, 173, 185, 187, 191, 193, 197, 199}) # up to 200 without tri()
      #skip.update({3527, 3707, 3947, 3989, 5164}) # with tri
      
      # target values to print
      tgt = arg(None, 0, Q)
      
      # number of 4's to use in constructions (<= 4)
      N = 4
      
      # find values using 4 digits
      # <m> is first missing number
      def solve(m=0):
        n = 0  # number of operations
      
        # start with the literals
        (V, upd) = (lits, None)
      
        while True:
          printf("[{n} iterations]")
          n += 1
          while True:
            if m in skip:
              v = "<skip>"
            else:
              v = V[N].get(m) 
              if v is None: break
            if tgt is None: printf("{m} = {v}")
            m += 1
          printf("[first missing = {m}]\n")
          if n > 1 and not upd: return
      
          # apply the operations to values in V
          upd = dict()
      
          # consider unary operations
          for (_, fn) in ops[1].items():
            for k in irange(1, N):
              for v in V[k].items():
                try:
                  (v_, r_) = fn(v)
                  if v_ is None: continue
                except ArithmeticError:
                  continue
                # record new values
                if k == 4 and v_ == tgt: printf("{tgt} = {r_}")
                if v_ not in V[k] and (k, v_) not in upd: upd[(k, v_)] = r_
      
          # consider binary operations
          for (_, fn) in ops[2].items():
            # combinations of up to 4 digits
            for (a, b) in [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (3, 1)]:
              k = a + b
              if k > N: continue
              for (va, vb) in product(V[a].items(), V[b].items()):
                try:
                  (v_, r_) = fn(va, vb)
                  if v_ is None: continue
                except ArithmeticError:
                  continue
                if k == 4 and v_ == tgt: printf("{tgt} = {r_}")
                # record new values
                if v_ not in V[k] and (k, v_) not in upd: upd[(k, v_)] = r_
      
          # apply the updates
          for ((k, v), r) in upd.items(): V[k][v] = r
      
      
      solve()
      

      Like

      • Jim Randell's avatar

        Jim Randell 1:53 pm on 30 January 2022 Permalink | Reply

        Although the clarification specifically excludes an “integer part of” function, if we do include it (as int()) we can get up to 23898.

        113 = int(((4 ^ 4) / fact(4)) ^ sqrt(4))

        157 = int(fact(4 + 4) / (4 ^ 4))

        3527 = int(tri((tri(4) + tri(4)) ^ 4) / fact(tri(4)))

        3707 = int((tri(tri(fact(4))) × sqrt(4) / fact(4)) − tri(tri(4)))

        3947 = int(tri(tri(tri(tri(4)))) / tri(fact(4)) − 4 − 4)

        3989 = int(sqrt(4) + (tri(tri(4)) + tri(tri(tri(4)))) / .4)

        5164 = int(tri(tri(tri(fact(4)))) / fact(tri(sqrt(4)) × tri(4 ^ 4)))

        23898 = tri(fact(tri(sqrt(4)))) + tri(tri(fact(4) + tri(sqrt(4)))) / tri(sqrt(4))
        23899 = ???

        Like

  • Unknown's avatar

    Jim Randell 4:25 pm on 28 January 2022 Permalink | Reply
    Tags:   

    Teaser 3097: Crazy golf 

    From The Sunday Times, 30th January 2022 [link] [link]

    Ian was trying to entertain John and Ken, his 2 young nephews, in the local park, which had a 9-hole crazy golf course. He decided to play a round with each of them separately, and gave them money for each hole he lost on a rising scale. He would pay £1 if he lost the first hole (or the first hole after winning one), then £2 if he lost the next consecutive hole, and £3 for the third, and so on.

    In the event, Ian won only 5 holes in total between the two rounds, including the first hole against John and the last hole against Ken. There were no ties. At the reckoning after both rounds, both boys received equal amounts of money.

    How much did it cost Uncle Ian?

    [teaser3097]

     
    • Jim Randell's avatar

      Jim Randell 4:47 pm on 28 January 2022 Permalink | Reply

      Each boy loses a hole at one end of the course, so we can just consider course with 8 holes, as we are only interested in groups of consecutive wins.

      This Python program runs in 47ms.

      Run: [ @replit ]

      from enigma import (irange, subsets, intersect, printf)
      
      # consider a course with 8 holes
      holes = irange(1, 8)
      
      # calculate the winnings for a nephew who wins holes <ws>
      def winnings(ws):
        (t, h) = (0, 0)
        for n in holes:
          if n in ws:
            h += 1
            t += h
          else:
            h = 0
        return t
      
      # choose 5 to 8 extra holes for J and K
      X = dict()
      for n in irange(5, 8):
        X[n] = set(winnings(ws) for ws in subsets(holes, size=n))
      
      # consider number of holes won by J
      for j in irange(5, 8):
        k = 13 - j
        # look for equal amounts
        for w in intersect([X[j], X[k]]):
          printf("I pays {t} [J wins {j}; K wins {k}]", t=w + w)
      

      Solution: Ian paid £32 to the boys.

      Ian lost to one of the boys on 5 consecutive holes and 1 other, paying (1 + 2 + 3 + 4 + 5) + 1 = £16.

      And to the other boy on 4 consecutive holes and another 3 consecutive holes, playing (1 + 2 + 3 + 4) + (1 + 2 + 3) = £16.

      So, in total Ian pays £32 for the 13 holes he lost.

      From 8 holes there are 6 ways that runs of 5 and 1 can be made:

      (1 2 3 4 5) (7)
      (1 2 3 4 5) (8)
      (2 3 4 5 6) (8)
      (1) (3 4 5 6 7)
      (1) (4 5 6 7 8)
      (2) (2 5 6 7 8)

      And there are 2 ways that runs of 4 and 3 can be made:

      (1 2 3 4) (6 7 8)
      (1 2 3) (5 6 7 8)

      So if John wins 5+1 and Ken wins 4+3 there are 12 possibilities.

      And if John wins 4+3 and Ken wins 5+1 there are also 12 possibilities.

      Giving 24 possible ways to achieve the required games.


      Manually, we see that the boys won 13 holes between them, so the possible splits are (8, 5) or (7, 6).

      Winning 8 holes would give a prize of T(8) which must be more than the winnings from 5 holes. So the splits are (7, 6).

      Possible consecutive runs for 7 (and corresponding prizes) are:

      (7) → T(7) = 28
      (1, 6) → T(1) + T(6) = 22
      (2, 5) → T(2) + T(5) = 18
      (3, 4) → T(3) + T(4) = 16

      Possible runs for 6 (and corresponding prizes) are:

      (6) → T(6) = 21
      (1, 5) → T(1) + T(5) = 16
      (2, 4) → T(2) + T(4) = 13
      (3, 3) → T(3) + T(3) = 12
      (1, 1, 4) → T(1) + T(1) + T(4) = 12
      (1, 2, 3) → T(1) + T(2) + T(3) = 10
      (2, 2, 2) → T(2) + T(2) + T(2) = 9

      The only overlap is for a prize of £16, with consecutive runs of (3, 4) and (1, 5).

      Like

      • Jim Randell's avatar

        Jim Randell 11:04 am on 29 January 2022 Permalink | Reply

        Here’s an alternative approach, which instead of generating the numbers of the holes won, finds possible runs of wins among the 8 holes.

        It is slightly faster than my original solution (above).

        Run: [ @replit ]

        from enigma import (irange, decompose, tri, intersect, printf)
        
        # generate possible runs of <n> wins for <k> holes
        def generate(n, k):
          # split n into j parts
          for j in irange(1, k + 1 - n):
            yield from decompose(n, j, sep=0)
        
        # consider winning runs totalling 5-8 holes on an 8 hole course
        X = dict()
        for n in irange(5, 8):
          X[n] = set(sum(tri(x) for x in ws) for ws in generate(n, 8))
        
        # consider number of holes won by J
        for j in irange(5, 8):
          k = 13 - j
          # look for equal winnings
          for w in intersect([X[j], X[k]]):
            printf("I pays {t} [J wins {j}; K wins {k}]", t=w + w)
        

        Like

  • Unknown's avatar

    Jim Randell 9:31 am on 27 January 2022 Permalink | Reply
    Tags: ,   

    Teaser 2879: Blood line 

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

    Patients numbered 1 to 99 were waiting for a blood test. George’s and Martha’s numbers were consecutive. Patients were called in [a] random order to one of the available cubicles numbered 1 to 9. The nurse in each cubicle took a fixed whole number of minutes to do the test, but that time varied from cubicle to cubicle. All cubicles started at 10am and they all finished together before 5pm on the same day. Amazingly, it turned out that each patient’s cubicle number was the highest digit that divided into their patient number. George noted that, when he was called, the session had been running for a number of minutes whose digits [when] added to[gether gave] his cubicle number. Martha noted that the same was true for her.

    What were their patient numbers?

    Unfortunately this puzzle has multiple solutions (apparently introduced by the editing process for puzzles at the paper).

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

    [teaser2879]

     
    • Jim Randell's avatar

      Jim Randell 9:31 am on 27 January 2022 Permalink | Reply

      The following program finds 5 possible pairs of patient numbers that satisfy the conditions.

      We know which cubicle each patient is to visit, so we can form them into queues for that cubicle.

      The session lasts for less than 7 hours = 420 minutes, and the cubicles finish at the same time. So the total length of the session must be a multiple of the length of each queue. (And it turns out there is only one possible duration).

      We can now calculate the time taken for each cubicle, and look for cubicles that have elapsed call times with a digit sum that is the same as the cubicle number.

      Then we can look for consecutive patient numbers that are called to these cubicles, and these give us possible patient numbers for Martha and George.

      The following Python program runs in 50ms.

      Run: [ @replit ]

      from enigma import (irange, peek, group, call, mlcm, dsum, tuples, union, printf)
      
      # map patients to queue number
      ns = irange(1, 99)
      queue = lambda n: peek(d for d in irange(9, 1, step=-1) if n % d == 0)
      n2q = dict((n, queue(n)) for n in ns)
      
      # form the queues
      qs = group(ns, by=(lambda n: n2q[n]))
      
      # consider the total length of the session < 7h = 420m
      m = call(mlcm, map(len, qs.values()))
      for t in irange(m, 419, step=m):
        printf("duration = {t} mins")
      
        # find cubicles with elapsed call times that sum to their digit
        ks = set()
        for (k, vs) in qs.items():
          x = t // len(vs)
          for s in irange(x, t - x, step=x):
            if dsum(s) == k:
              printf("queue {k}; {x} mins/test; call at {s} mins")
              ks.add(k)
      
        # find consecutive numbers for patients in queues in ks
        for (a, b) in tuples(sorted(union(qs[k] for k in ks)), 2):
          if b == a + 1:
            printf("({a}, {b}) -> ({qa}, {qb})", qa=n2q[a], qb=n2q[b])
      

      Solution: The are 5 possible pairs of patient numbers for Martha and George: (26, 27), (44, 45), (45, 46), (62, 63), (81, 82).


      After constructing the queues for each of the digits 1-9, we see that the only possible duration of the session is 264 minutes, and there are 6 possible times when a patient could be called such that the digit sum of the elapsed number of minutes is the same as the cubicle number.

      called at 72 minutes to cubicle 9
      called at 110 minutes to cubicle 2
      called at 132 minutes to cubicle 6
      called at 144 minutes to cubicle 9
      called at 216 minutes to cubicle 9
      called at 220 minutes to cubicle 4

      This means that we can have the following consecutive numbers for George and Martha:

      26 & 27 → called to cubicle 2 (after 110 minutes) and cubicle 9 (after 72, 144, or 216 minutes)
      44 & 45 → called to cubicle 4 (after 220 minutes) and cubicle 9 (after 72, 144, or 216 minutes)
      45 & 46 → called to cubicle 9 (after 72, 144, or 216 minutes) and cubicle 2 (after 110 minutes)
      62 & 63 → called to cubicle 2 (after 110 minutes) and cubicle 9 (after 72, 144, or 216 minutes)
      81 & 82 → called to cubicle 9 (after 72, 144, or 216 minutes) and cubicle 2 (after 110 minutes)

      The additional constraint that “George and Martha were called less than half an hour apart” would narrow these down to a single solution:

      44 & 45 → called to cubicle 4 (after 220 minutes) and cubicle 9 (after 216 minutes)

      Like

  • Unknown's avatar

    Jim Randell 9:47 am on 25 January 2022 Permalink | Reply
    Tags:   

    Brain-Teaser 904: The six ages 

    From The Sunday Times, 18th November 1979 [link]

    Problems concerning ages have always proved fruitful and entertaining exercises to both mathematicians and non-mathematicians. Trial and error methods, calculators and normal or esoteric mathematical techniques can all be deployed to find the correct solution. The most elegant or the most economical method is naturally the most commendable, but the correct solution, however obtained, is the desideratum.

    Our problem concerns six men whose ages are within the range 21 to 89 and any two of them differ by at least 9. If we take the two digits comprising each of the ages of three of the men, and reverse them, we obtain the ages of the other three men.

    What is more, if we take the sum of the ages of the first group, we find that it equals the sum of the ages of the second group of three.

    Also the sum of the squares of the three ages of the first group equals the sum of the squares of the ages of the second group of three.

    Finally, one of the ages in each group is exactly twice an age in the other group.

    What are the ages of the six men (in increasing order)?

    This puzzle appeared in the first issue of The Sunday Times to be published in nearly a year (after it was hit by industrial action). The previous issue having been published on 26th November 1978 (almost one year earlier).

    [teaser904]

     
    • Jim Randell's avatar

      Jim Randell 9:48 am on 25 January 2022 Permalink | Reply

      I used the [[ SubstitutedExpression ]] solver from the enigma.py library to solve this puzzle.

      The following run file executes in 66ms. (The internal run time of the generated program is 2.17ms).

      Run: [ @replit ]

      #! python3 -m enigma -rr
      
      # suppose the ages are: AB CD EF; BA DC FE
      
      SubstitutedExpression
      
      --digits="2-8"
      
      # suppose AB CD EF are in order, and AB is the smallest of the 6 ages
      "AB < CD" "CD < EF"
      "AB < BA" "AB < DC" "AB < FE"
      
      # differences are all at least 9
      "all(abs(x - y) > 8 for (x, y) in subsets([AB, CD, EF, BA, DC, FE], size=2))"
      
      # sums of the 2 groups are equal
      "AB + CD + EF == BA + DC + FE"
      
      # sums of the squares of the 2 groups are equal
      "sumsq([AB, CD, EF]) == sumsq([BA, DC, FE])"
      
      # in each group one of the ages is twice one of the ages in the other group
      "any(2 * x in {BA, DC, FE} for x in {AB, CD, EF})"
      "any(2 * x in {AB, CD, EF} for x in {BA, DC, FE})"
      
      # answer is the ages in order
      --answer="ordered(AB, CD, EF, BA, DC, FE)"
      
      # [optional]
      --template="(AB CD EF) (BA DC FE)"
      --solution=""
      

      Solution: The ages are: 23, 32, 46, 64, 78, 87.

      The two sets being: (23, 64, 78) and (32, 46, 87).

      Like

      • Jim Randell's avatar

        Jim Randell 12:23 pm on 29 January 2022 Permalink | Reply

        Some observations allow us to write a program that runs even faster.

        Suppose the six ages are (AB, CD, EF) and (BA, DC, FE).

        Each of them is between 21 and 89. So A, C, E are digits from 2-8 (as they are tens digits in the first set), and so are B, D, F (as they are tens digits in the second set).

        And the digits must all be different as the numbers are all at least 9 apart (so we can’t have two numbers with the same tens digit).

        The sums of the two sets are equal:

        AB + CD + EF = BA + DC + FE
        A + C + E = B + D + F

        And the sums of the squares are equal:

        AB² + CD² + EF² = BA² + DC² + FE²
        A² + C² + E² = B² + D² + F²

        So we can start by looking for two disjoint sets of digits from 2-8 with the same “sum of squares” value and also the same sum. (It turns out there is only one such set).

        We can then pair up the digits into two sets of ages, where each set contains an age that is twice one of the ages in the other set.

        This Python program runs in 50ms (with an internal runtime of just 246µs ).

        from enigma import (irange, subsets, group, sumsq, nconcat, tuples, printf)
        
        # group sets of 3 digits by the sum of their squares
        d = group(subsets(irange(2, 8), size=3), by=sumsq)
        
        # look for two disjoint sets with the same sum
        for vs in d.values():
          for (s1, s2) in subsets(vs, size=2):
            if not (sum(s1) == sum(s2) and len(set(s1 + s2)) == 6): continue
        
            # form the numbers
            (A, C, E) = s1
            for (B, D, F) in subsets(s2, size=3, select="P"):
              ns1 = set(map(nconcat, [(A, B), (C, D), (E, F)]))
              ns2 = set(map(nconcat, [(B, A), (D, C), (F, E)]))
        
              # check each set contains an element that is double one of the others
              if not any(2 * x in ns2 for x in ns1): continue
              if not any(2 * x in ns1 for x in ns2): continue
        
              # construct the answer
              ns = sorted(ns1.union(ns2))
              # check no numbers are within 9 of each other
              if any(b - a < 9 for (a, b) in tuples(ns, 2)): continue
        
              printf("{ns} [{ns1} + {ns2}]", ns1=sorted(ns1), ns2=sorted(ns2))
        

        Like

    • GeoffR's avatar

      GeoffR 3:35 pm on 25 January 2022 Permalink | Reply

      
      % A Solution in MiniZinc
      include "globals.mzn";
      
      var 1..9:A; var 1..9:B; var 1..9:C; 
      var 1..9:D; var 1..9:E; var 1..9:F;
      
      % Digits for two groups of ages
      constraint all_different([A, B, C, D, E, F]);
      
      % First group
      var 21..89: AB = 10*A + B;
      var 21..89: CD = 10*C + D;
      var 21..89: EF = 10*E + F;
      
      % Second group - ages reverse of 1st group
      var 21..89: BA = 10*B + A;
      var 21..89: DC = 10*D + C;
      var 21..89: FE = 10*F + E;
      
      % Order ages
      constraint BA > AB /\ AB < CD /\ CD < EF
      /\ BA < DC /\ DC < FE; 
      
      % Any two of the ages differ by at least 9
      constraint 
         abs(AB-CD) >=9 /\ abs(AB-EF) >=9 /\ abs(AB-BA) >=9
      /\ abs(AB-DC) >=9 /\ abs(AB-FE) >=9 /\ abs(CD-EF) >=9 
      /\ abs(CD-BA) >=9 /\ abs(CD-DC) >=9 /\ abs(CD-FE) >=9
      /\ abs(EF-BA) >=9 /\ abs(EF-DC) >=9 /\ abs(EF-FE) >=9
      /\ abs(BA-DC) >=9 /\ abs(BA-FE) >=9 /\ abs(DC-FE) >=9;
      
      % Sum of ages of the first group = sum of ages of the second group
      constraint AB + CD + EF == BA + DC + FE;
      
      % Sum of the squares of the three ages of the first group 
      % equals sum of the squares of the three ages of the second group
      constraint AB*AB + CD*CD + EF*EF == BA*BA + DC*DC + FE*FE;
      
      % One of the ages in each group is exactly twice an age in the other group
      %
      % *** This teaser condition was not needed to give the single answer ***
      % Output shows 64 = 2 * 32 and 46 = 2 * 23, which satisfies this condition.
      
      solve satisfy;
      
      output ["1st ages group = " ++ show(AB) ++ ", " ++ show(CD)
       ++  ", " ++ show(EF) ++ "\n"
      ++ "2nd ages group = " ++ show(BA) ++ ", " ++ show(DC) 
      ++ ", " ++ show(FE) ];
      
      % 1st ages group = 23, 64, 78
      % 2nd ages group = 32, 46, 87
      % ----------
      % ==========
      % Sorted ages:  23, 32, 46, 64, 78, 87
      
      

      Like

      • Jim Randell's avatar

        Jim Randell 4:43 pm on 25 January 2022 Permalink | Reply

        @GeoffR:

        Without the “in each group one of the ages is twice one of the ages in the other group” condition there is a further solution:

        (28, 64, 73) and (82, 46, 37)

        So it is needed.

        Like

    • GeoffR's avatar

      GeoffR 5:41 pm on 25 January 2022 Permalink | Reply

      @Jim: OK. I see you got a 2nd solution, justifying the constraint.

      For me, MinZinc only came up with the single solution, even though I had set multiple output configuration to 5 solutions.

      On the Configuration Menu, I tried both unchecking and checking the check-box with the heading “Stop after this many solutions(uncheck for all). I am using the MiniZinc IDE under Windows 10.

      Like

      • Jim Randell's avatar

        Jim Randell 9:46 pm on 25 January 2022 Permalink | Reply

        @GeoffR:

        The problem is your ordering constraint is over specified.

        Try:

        constraint AB < CD /\ CD < EF /\ AB < BA /\ AB < DC /\ AB < FE; 
        

        Like

    • GeoffR's avatar

      GeoffR 10:48 am on 26 January 2022 Permalink | Reply

      @Jim: Thanks, that solved my ordering constraint issue.

      I used your suggested ordering constraint in my code and got the two solutions. It then needs the “in each group one of the ages is twice one of the ages in the other group” constraint to get the single answer.

      Like

    • GeoffR's avatar

      GeoffR 11:22 am on 26 January 2022 Permalink | Reply

      % A Solution in MiniZinc - revised programme
      include "globals.mzn";
      
      var 1..9:A; var 1..9:B; var 1..9:C; 
      var 1..9:D; var 1..9:E; var 1..9:F;
      
      % Digits for two groups of ages are different
      constraint all_different([A, B, C, D, E, F]);
      
      % First group
      var 21..89: AB = 10*A + B;
      var 21..89: CD = 10*C + D;
      var 21..89: EF = 10*E + F;
      
      % Second group - ages reverse of 1st group
      var 21..89: BA = 10*B + A;
      var 21..89: DC = 10*D + C;
      var 21..89: FE = 10*F + E;
      
      % Revised ordering constraint (Jim)
      constraint AB < CD /\ CD < EF /\ AB < BA /\ AB < DC /\ AB < FE; 
      
      % Any two of the ages differ by at least 9
      constraint 
         abs(AB-CD) >=9 /\ abs(AB-EF) >=9 /\ abs(AB-BA) >=9
      /\ abs(AB-DC) >=9 /\ abs(AB-FE) >=9 /\ abs(CD-EF) >=9 
      /\ abs(CD-BA) >=9 /\ abs(CD-DC) >=9 /\ abs(CD-FE) >=9
      /\ abs(EF-BA) >=9 /\ abs(EF-DC) >=9 /\ abs(EF-FE) >=9
      /\ abs(BA-DC) >=9 /\ abs(BA-FE) >=9 /\ abs(DC-EF) >=9;
      
      % Sum of ages of the first group = sum of ages of the second group
      constraint AB + CD + EF == BA + DC + FE;
      
      % Sum of the squares of the three ages of the first group 
      % equals sum of the squares of the three ages of the second group
      constraint AB*AB + CD*CD + EF*EF == BA*BA + DC*DC + FE*FE;
      
      % One of the ages in each group is exactly twice an age in the other group
      % One of 1st ages group is double one of 2nd group
      constraint 
         (AB == 2*BA \/ AB == 2*DC \/ AB == 2*FE)
      \/ (CD == 2*BA \/ CD == 2*DC \/ CD == 2*FE)
      \/ (EF == 2*BA \/ EF == 2*DC \/ EF == 2*FE);
      
      % One of 2nd ages group is double one of 1st group
      constraint 
         (BA == 2*AB \/ BA == 2*CD \/ BA == 2*EF)
      \/ (DC == 2*AB \/ DC == 2*CD \/ DC == 2*EF)
      \/ (FE == 2*AB \/ FE == 2*CD \/ FE == 2*EF);
      
      solve satisfy;
      
      output ["1st ages group = " ++ show(AB) ++ ", " ++ show(CD)
       ++  ", " ++ show(EF) ++ "\n"
      ++ "2nd ages group = " ++ show(BA) ++ ", " ++ show(DC) 
      ++ ", " ++ show(FE) ];
      
      % 1st ages group = 23, 64, 78
      % 2nd ages group = 32, 46, 87
      % ----------
      % ==========
      
      
      
      

      Like

    • Hugh+Casement's avatar

      Hugh+Casement 7:17 am on 30 January 2022 Permalink | Reply

      Without the upper and lower age limits
      there would be another solution: 14, 82, 69 and 41, 28, 96,
      again with group sum 165.

      Like

  • Unknown's avatar

    Jim Randell 10:31 am on 23 January 2022 Permalink | Reply
    Tags:   

    A Brain Teaser: [Grains of rice] 

    From The Sunday Times, 21st December 1952 [link]

    An Eastern potentate, at the end of a game of chess with his professional chess player, broached the delicate question of a reward for his many years of service.

    The old man pointed to the board and said: “Suppose we number the squares from 1 to 64, thus. Your Majesty will observe that your King is on a lower-numbered square than mine. Pay me, I humbly beg, in grains of rice, for each square as many as the number of that square raised to the power of the number of the square occupied by your King, finishing at and including the square occupied by my King”.

    “But that will be ruinous”, protested the monarch. “Not so, for the sum total contains but nine figures”.

    “Then be it so. But will you take payment to the nearest thousand?”. “Certainly”, replied the sage, since if your men count accurately, I shall thereby forfeit only eight grains of rice”.

    What squares were occupied by the two Kings, and how many grains were the old man’s reward?

    This one of the occasional Holiday Brain Teasers published in The Sunday Times prior to the start of numbered Teasers in 1961. Prizes of 3 guineas and 2 guineas were offered.

    This puzzle was originally published with no title.

    [teaser-1952-12-21] [teaser-unnumbered]

     
    • Jim Randell's avatar

      Jim Randell 10:32 am on 23 January 2022 Permalink | Reply

      If the king is on square k, and the old man is on square j then the total number of grains t is given by:

      t = sum (i = 1 .. j) (i^k)

      This Python program runs in 52ms.

      Run: [ @replit ]

      from enigma import (irange, ndigits, printf)
      
      # consider the king's square
      for k in irange(1, 63):
        # t = total number of grains
        # j = old man's square
        t = j = 0
        while j < 64:
          j += 1
          t += j**k
          n = ndigits(t)
          if n > 9: break
          # check conditions
          if n == 9 and k < j and t % 1000 == 8:
            printf("k={k} j={j} t={t}")
      

      Solution: The kings are on squares 5 and 32. The reward consisted of 196,171,000 grains of rice.

      The actual total being:

      >>> sum(powers(1, 32, 5))
      196171008
      

      A grain of rice weighs approximately 1/64 gram, so the total prize would be just over 3065 kg of rice.

      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