Updates from February, 2023 Toggle Comment Threads | Keyboard Shortcuts

  • Unknown's avatar

    Jim Randell 9:30 am on 14 February 2023 Permalink | Reply
    Tags:   

    Teaser 2717: Round the garden 

    From The Sunday Times, 19th October 2014 [link] [link]

    George and Martha’s garden is a quadrilateral with each of its sides a whole number of metres in length. When Martha wrote down the lengths of the four sides together with the length of the perimeter, she noticed that overall these five numbers used each of the ten digits exactly once. Also, the lengths of the three longest sides of the garden were prime numbers. She told George, but he was unable to work out all the lengths until she also told him that no two of the four lengths differed by a prime number.

    What are the four lengths?

    [teaser2717]

     
    • Jim Randell's avatar

      Jim Randell 9:31 am on 14 February 2023 Permalink | Reply

      This Python program finds candidate sets of sides of the quadrilateral such that the three longest sides are prime, and together with the fourth side and the calculated perimeter each of the digits 0-9 is used exactly once.

      We then check the candidate solutions for sets where no pair of lengths differ by a prime, and this gives a unique solution.

      The following Python program runs in 62ms. (Internal runtime is 11ms).

      Run: [ @replit ]

      from enigma import (primes, nsplit, irange, empty, rev, subsets, sq, printf)
      
      # combine digits of <n> with existing digits <ds>
      # digits cannot be used more than once
      def digits(n, ds):
        ds = set(ds)
        for d in nsplit(n):
          if d in ds: return
          ds.add(d)
        return ds
      
      # find sets of numbers that between them and their sum use each of the
      # 10 digits exactly once such that the largest 3 numbers are prime.
      # return: ((a, b, c, d), s); where a < b < c < d, s = a + b + c + d
      def solve(ns=[], ds=empty):
        k = len(ns)
        # are we done?
        if k == 4:
          # calculate the sum of the numbers
          t = sum(ns)
          # which should bring the digits used to 10
          ds_ = digits(t, ds)
          if ds_ is not None and len(ds_) == 10:
            yield (rev(ns), t)
        else:
          # first 3 numbers are primes, but final number is not necessarily a prime
          a = 1
          b = (111 if k == 0 else ns[-1] - 1)
          nrange = (irange if k == 3 else primes.irange)
          for n in nrange(a, b):
            # check for new distinct digits
            ds_ = digits(n, ds)
            if ds_ is not None:
              yield from solve(ns + [n], ds_)
      
      # quadrilateral check
      def is_quad(ss):
        if len(ss) != 4: return
        (a, b, c, d) = ss
        # a + b + c > d
        if not (a + b + c > d): return
        # a^2 + b^2 + c^2 > d^2 / 3
        (a2, b2, c2, d2) = map(sq, (a, b, c, d))
        if 3 * (a2 + b2 + c2) <= d2: return
        # a^4 + b^4 + c^4 >= d^4 / 27
        (a4, b4, c4, d4) = map(sq, (a2, b2, c2, d2))
        if 27 * (a4 + b4 + c4) < d4: return
        # looks OK
        return 1
      
      # difference check: no pair of lengths differs by a prime
      diff = lambda ss: not any(primes.is_prime(y - x) for (x, y) in subsets(ss, size=2))
      
      # collect possible sides and perimeters
      for (ss, p) in solve():
        if not is_quad(ss): continue
        # apply difference check
        d = diff(ss)
        printf("{ss} -> {p}; diff = {d}")
      

      Solution: The sides of the quadrilateral are (in metres): 4, 53, 61, 89.

      And the perimeter is 207 m:

      4 + 53 + 61 + 89 = 207

      Without the additional condition that no two of the lengths differ by a prime number there is a second candidate solution:

      4 + 59 + 61 + 83 = 207

      But this fails the difference test (as: 83 − 4 = 79, and 61 − 59 = 2, both of which are primes).


      If we assume the garden is a convex quadrilateral, then the length 4 side is considerably shorter than the other 3 sides, so the shape of the garden is roughly a (59, 61, 83) triangle.

      We can take this triangle and “open out” two of the sides until we have introduced a gap of 4 between them. To give us shapes like this:

      Like

    • GeoffR's avatar

      GeoffR 4:36 pm on 14 February 2023 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";
      
      predicate is_prime(var int: x) = 
      x > 1 /\ forall(i in 2..1 + ceil(sqrt(int2float(ub(x))))) 
      ((i < x) -> (x mod i > 0));
      
      % Digits for quadrilateral sides and perimeter
      % Assumed sides are A, BC, DE, FG and HIJ for the ten digits
      var 1..9:A; var 1..9:B; var 1..9:C; var 1..9:D;
      var 1..9:E; var 1..9:F; var 1..9:G; var 0..9:H;
      var 0..9:I; var 1..9:J;
      
      % The ten digits are used exactly once
      constraint all_different([A, B, C, D, E, F, G, H, I, J]);
      
      % Ordering values of quadrilateral sides
      constraint A < BC /\ BC < DE /\ DE < FG;
      
      % Quadrilateral sides are, A, BC, DE, FG
      var 10..99:BC = 10*B + C;
      var 10..99:DE = 10*D + E;
      var 10..99:FG = 10*F + G;
      constraint A + BC + DE > FG;
      
      % Perimeter of quadrilateral
      var 100..999: HIJ = 100*H + 10*I + J;
      constraint HIJ = A + BC + DE + FG;
      
      % Three largest sides of the quadrilateral are prime
      constraint is_prime(BC) /\ is_prime(DE) /\ is_prime(FG);
      
      % No two sides differ by a prime number
      constraint sum( [is_prime(BC - A), is_prime(DE - A), is_prime(FG - A),
      is_prime(DE - BC), is_prime(FG - BC), is_prime(FG - DE)]) == 0;
      
      solve satisfy;
      
      output ["[A, BC, DE, FG, HIJ] = " ++ show([A, BC, DE, FG, HIJ]) ];
      
      % [A, BC, DE, FG, HIJ] = [4, 53, 61, 89, 207]
      % ----------
      % ==========
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 9:14 am on 7 February 2023 Permalink | Reply
    Tags: ,   

    Teaser 2692: Runners-up 

    From The Sunday Times, 27th April 2014 [link] [link]

    In our local football league each team plays each other team twice each season, once at home and once away. The teams get three points for a win and one point for a draw. All games are on Saturdays at 3pm, and yesterday all the teams played their last game, so the final league table has now been published. Our team were runners-up, but we should have won! We were just one point behind the winners and, although they won two-thirds of their games, our team won more. Furthermore, looking at our drawn games, I notice that the league winners lost twice as many games as we drew.

    How many games did the league winners win, draw and lose?

    [teaser2692]

     
    • Jim Randell's avatar

      Jim Randell 9:15 am on 7 February 2023 Permalink | Reply

      This puzzle should have been worded more carefully to eliminate multiple solutions.

      If there are n teams in the league, then each team plays each of the other (n − 1) teams both at home and away, so each team plays (2n − 2) matches.

      The fact that all teams can play at one time tells us that n must be even (so the teams can all be paired up).

      We are not told how long the season is, but if we suppose that it lasts less than 1 year, then as the teams play 1 match per week, we can suppose than n ≤ 26 (otherwise it would not be possible to fit all the matches in).

      I am assuming that “the league winners lost twice as many games as we drew” implies that the numbers involved are non-zero (otherwise it would be a bit of an odd way to phrase it), but this does not give a unique solution.

      The following Python program runs in 52ms. (Internal runtime is 190µs).

      Run: [ @replit ]

      from enigma import (irange, inf, div, printf)
      
      # consider number of teams in the league (must be even)
      for n in irange(2, inf, step=2):
        # total number of matches played by each team
        played = 2 * (n - 1)
        if played > 52: break
        # the winners won 2/3 of their matches
        w1 = div(2 * played, 3)
        if w1 is None: continue
      
        # consider the number of draws for the runners up (at least 1)
        for d2 in irange(1, played):
          # the winners lost twice this amount
          l1 = 2 * d2
          # calculate the draws and points for the winners
          d1 = played - w1 - l1
          if d1 < 0: break
          pts1 = 3 * w1 + d1
          # calculate the points, wins for the runners up
          pts2 = pts1 - 1
          w2 = div(pts2 - d2, 3)
          if w2 is None or not (w2 > w1): continue
          l2 = played - w2 - d2
          if l2 < 0: continue
          # some sanity checks
          if not (w1 + l2 < played - 2 and w2 + l1 < played - 2): continue
          # output solution
          printf("n={n} d2={d2}: played={played}; (w, d, l, pts) #1 ({w1}, {d1}, {l1}, {pts1}); #2 ({w2}, {d2}, {l2}, {pts2})")
      

      There are two candidate solutions:

      16 teams in the league; each team plays 30 matches.

      winners: w=20, d=8, l=2, pts=68; runners up: w=22, d=1, l=7, pts=67
      winners: w=20, d=6, l=4, pts=66; runners up: w=21, d=2, l=7, pts=65

      The published answer (“20, 6 and 4”) corresponds to the second of these scenarios.

      It has been suggested that “looking at our drawn games” necessarily implies that the runners-up must have more than one drawn match (eliminating the first of the above solutions), but I think if this was the intention a clearer choice of words would be necessary.

      Like

  • Unknown's avatar

    Jim Randell 11:37 am on 2 February 2023 Permalink | Reply
    Tags:   

    Teaser 2704: Celebrity gardeners 

    From The Sunday Times, 20th July 2014 [link] [link]

    There were six celebrity gardeners at the local show:

    Beardshaw, Dimmock, Flowerdew, Greenwood, Klein, Thrower.

    Each of them was exhibiting two different shrubs from the following list:

    Abutilon, Azalea, Berberis, Cornus, Euonymus, Hibiscus, Holly, Magnolia, Potentilla, Spiraeas, Weigela, Wisteria.

    On each of six tables there was a card containing the gardener’s surname and the name of the two shrubs. For any two of the words on the same card, there were exactly two letters of the alphabet that occurred (perhaps more than once) in both.

    (a) Which two shrubs did Beardshaw exhibit?

    (b) Who exhibited the Abutilon?

    [teaser2704]

     
    • Jim Randell's avatar

      Jim Randell 11:37 am on 2 February 2023 Permalink | Reply

      We can solve this puzzle using the [[ grouping ]] solver from the enigma.py library.

      The following Python program runs in 51ms. (Internal runtime is 463µs).

      Run: [ @replit ]

      from enigma import grouping
      
      names = ('Beardshaw', 'Dimmock', 'Flowerdew', 'Greenwood', 'Klein', 'Thrower')
      
      plants = (
        'Abutilon', 'Azalea', 'Berberis', 'Cornus', 'Euonymus', 'Hibiscus',
        'Holly', 'Magnolia', 'Potentilla', 'Spiraeas', 'Weigela', 'Wisteria',
      )
      
      # form the 2-gangs
      for gs in grouping.gangs(2, names, plants, grouping.share_letters(2)):
        # output the groups
        grouping.output_gangs(names, gs)
      

      Solution: (a) Beardshaw exhibited: Cornus, Potentilla. (b) Abutilon was exhibited by Greenwood.

      Like

  • Unknown's avatar

    Jim Randell 11:22 am on 31 January 2023 Permalink | Reply
    Tags:   

    Teaser 2718: By the dozen 

    From The Sunday Times, 26th October 2014 [link] [link]

    I have written down a five-figure number that uses five different non-zero digits, and then I have replaced the digits by letters to give DOZEN. Within this it is possible to see various numbers, namely:

    D, O, Z, E, N
    DO, OZ, ZE, EN
    DOZ, OZE, ZEN
    DOZE, OZEN
    DOZEN

    Surprisingly, the original number is divisible by a dozen or more of these.

    What is the number DOZEN?

    [teaser2718]

     
    • Jim Randell's avatar

      Jim Randell 11:23 am on 31 January 2023 Permalink | Reply

      Of the 15 fragments, there can be at most 3 of them that do not divide into DOZEN, and we don’t need to check that DOZEN divides into itself, so we just need to check that at most 3 of the fragments of length 1 to 4 do not.

      This Python program runs in 193ms. (Internal runtime is 92ms).

      Run: [ @replit ]

      from enigma import (irange, tuples, nconcat, subsets, icount_at_most, printf)
      
      # construct fragments of sequence <seq>, of size <ks>
      def fragments(seq, ks):
        for k in ks:
          for t in tuples(seq, k):
            yield t
      
      # consider 5 different digits
      for ds in subsets(irange(1, 9), size=5, select="P"):
        n = nconcat(ds)
        # fragments of length 1-4
        fs = fragments(ds, irange(1, 4))
        # at most 3 of the fragments do not divide into n
        fn = lambda ds: n % nconcat(ds) != 0
        if icount_at_most(fs, fn, 3):
          # output solution
          printf("DOZEN = {n}")
      

      Solution: DOZEN = 31248.

      There are 3 fragments that do not divide 31248. These are: 312, 3124, 1248.

      And the remaining 12 fragments do divide 31248.

      Like

    • GeoffR's avatar

      GeoffR 1:55 pm on 31 January 2023 Permalink | Reply

      As a contrast, I checked for eleven fragments which do divide the five digit number.
      With the five digit number itself, this is equivalent to twelve divisions. I did not consider it necessary check for more than twelve divisions.

      
      % A Solution in MiniZinc
      include "globals.mzn";
      
      var 1..9:D; var 1..9:O; var 1..9:Z; var 1..9:E; var 1..9:N;
      
      constraint all_different([D, O, Z, E, N]);
      
      var 10..99:DO = 10*D + O;
      var 10..99:OZ = 10*O + Z;
      var 10..99:ZE = 10*Z + E;
      var 10..99:EN = 10*E + N;
      var 100..999:DOZ = 100*D + 10*O + Z;
      var 100..999:OZE = 100*O + 10*Z + E;
      var 100..999:ZEN = 100*Z + 10*E + N;
      var 1000..9999: DOZE = 1000*D + 100*O + 10*Z + E;
      var 1000..9000: OZEN = 1000*O + 100*Z + 10*E + N;
      var 10000..99999:DOZEN = 10000*D + 1000*O + 100*Z + 10*E + N;
      
      
      % % DOZEN divides itself, so only 11 fragment divisions to check
      constraint sum  
        ([DOZEN mod D == 0, DOZEN mod O == 0, DOZEN mod Z == 0,
          DOZEN mod E == 0, DOZEN mod N == 0, DOZEN mod DO == 0,
          DOZEN mod OZ == 0,DOZEN mod ZE == 0, DOZEN mod EN == 0,
          DOZEN mod DOZ == 0,DOZEN mod OZE == 0,DOZEN mod ZEN == 0,
          DOZEN mod DOZE == 0, DOZEN mod OZEN == 0]) == 11;
                       
      solve satisfy;
      
      output ["DOZEN = " ++ show(DOZEN) ];
                       
      % DOZEN = 31248
      % ----------
      % ==========
      
      

      Like

  • Unknown's avatar

    Jim Randell 4:32 pm on 18 January 2023 Permalink | Reply
    Tags:   

    Teaser 2708: Abracadabra 

    From The Sunday Times, 17th August 2014 [link] [link]

    In his magic cave Ali Baba discovers a string necklace comprising sixty various gold beads that he decides to melt down and turn into coins. Each bead is spherical but with a cylindrical hole symmetrically cut through it, and in each bead the hole is one centimetre long. Ali Baba melts down all these beads and makes the gold into circular coins of two centimetres diameter and half a centimetre thickness.

    How many coins does he obtain?

    [teaser2708]

     
    • Jim Randell's avatar

      Jim Randell 4:33 pm on 18 January 2023 Permalink | Reply

      If we start with a sphere of radius R, and bore a hole through it of radius r (from north pole to south pole) then we are left with a shape (known as a “napkin ring”), and we wish to determine its volume.

      First we note that the height of the napkin ring is given by the value 2h, where:

      h² = R² − r²

      Now consider a 2-dimensional slice through the napkin ring parallel to the equator of the sphere (i.e. along a line of latitude), at a height of y above (or below) the equator.

      The area of the circle belonging to the original sphere is:

      A = 𝛑 (R² − y²)

      And the area removed by the hole is (independent of y):

      a = 𝛑 r²

      And the area of the slice at height ±y is:

      S = 𝛑 (R² − y² − r²)

      or in terms of h:

      S = 𝛑 (h² − y²)

      So the area of slice depends only on h (the semi-height of the napkin ring) and y (the latitude at which the slice is taken).

      This means if we have two napkin rings with different (R, r) values, but the same h value, then the areas of cross-sections through the rings at latitudes in the interval [−h, h] will always be the same.

      We may then apply the 3-dimensional version of Cavalieri’s principle [@wikipedia] to deduce that two napkin rings with same height also have the same volume.

      And we can calculate this volume by considering a napkin ring with height 2h and a hole with radius 0. This is just a complete sphere with radius h.

      Hence the volume of any napkin ring with height 2h is:

      V = (4/3) 𝛑 h³


      So in this puzzle, it does not matter that we are only given the length of the hole through each bead. Each of the beads will have the same volume, even if they are based on spheres with different radii (the holes would also have to have different radii in order to give matching heights).

      Each of the beads has a height of 10mm, so the volume of each bead (in mm³) is:

      B = (4/3) 𝛑 (5³)
      B = (500/3) 𝛑

      And there are 60 beads, giving a total volume of gold (in mm³):

      G = 60B = 10000 𝛑

      Each coin produced has a radius of 10mm and a height of 5mm, so the volume (in mm³) of each coin is:

      C = 𝛑 (10²) 5 = 500 𝛑

      And the number of coins that can be produced (if there is no wastage) is:

      N = G / C = 20

      Hence:

      Solution: 20 coins can be made.


      See also: Napkin ring problem at Wikipedia.

      Like

  • Unknown's avatar

    Jim Randell 11:37 am on 16 January 2023 Permalink | Reply
    Tags: ,   

    Teaser 2709: Around America 

    From The Sunday Times, 24th August 2014 [link] [link]

    The 51 states of America have two-letter abbreviations:

    AK, AL, AR, AZ, CA, CO, CT, DC, DE, FL, GA, HI, IA,
    ID
    , IL, IN, KS, KY, LA, MA, MD, ME, MI, MN, MO, MS,
    MT
    , NC, ND, NE, NH, NJ, NM, NV, NY, OH, OK, OR,
    PA
    , RI, SC, SD, TN, TX, UT, VA, VT, WA, WI, WV, WY.

    I have written as many different letters as possible around a circle such that, if you look at any adjacent pair of letters, then clockwise they are one of the above abbreviations.

    One of my letters is R.

    Starting at R, list the letters clockwise.

    In the book The Sunday Times Brain Teasers Book 2 (2020), the abbreviation NI is given instead of NJ (which I believe was how the puzzle was originally published), but this has been corrected on The Sunday Times website.

    [teaser2709]

     
    • Jim Randell's avatar

      Jim Randell 11:39 am on 16 January 2023 Permalink | Reply

      (See also: Enigma 1754).

      The USA has 50 states and 1 federal district (DC), giving us 51 abbreviations in all. Although none of them are NI, but this was probably a typo for NJ (New Jersey), as it has been corrected on The Sunday Times website. And we get the same solution if NJ or NI are used.

      This Python program runs in 52ms. (Internal runtime is 250µs).

      Run: [ @replit ]

      from enigma import (group, item, Accumulator, printf)
      
      states = str.split(
        "AK AL AR AZ CA CO CT DC DE FL GA HI IA ID IL IN KS "
        "KY LA MA MD ME MI MN MO MS MT NC ND NE NH NJ NM NV "
        "NY OH OK OR PA RI SC SD TN TX UT VA VT WA WI WV WY"
      )
      
      # map letters to next letters
      g = group(states, by=item(0), f=item(1), fn=set)
      
      # generate possible circular chains of letters
      def solve(s):
        # possible next letters
        xs = g.get(s[-1])
        if not xs: return
        # does the sequence form a chain?
        if len(s) > 1 and s[0] in xs:
          yield s
        # try to extend the sequence
        for x in xs.difference(s):
          yield from solve(s + x)
      
      # find maximal chains starting with 'R'
      r = Accumulator(fn=max, collect=1)
      for s in solve('R'):
        r.accumulate_data(len(s), s)
      
      # output solution
      printf("[max length = {r.value}]")
      for s in r.data:
        printf("chain = [{s}]")
      

      Solution: The maximal length chain is: RILAKSDCTNMO (12 letters).

      Making the following 12 states: RI, IL, LA, AK, KS, SD, DC, CT, TN, NM, MO, OR.


      Starting with the earliest letter in the alphabet we can write this maximal length chain as:

      AKSDCTNMORIL

      There is another length 12 chain that does not include R:

      AKSDCTNMOHIL

      And if we wish to include V the longest chains have length 10:

      AKSDCORINV
      AKSDCOHINV

      Like

    • Jim Randell's avatar

      Jim Randell 12:18 pm on 16 January 2023 Permalink | Reply

      Here is a variation on this puzzle:

      If the state abbreviations (above) are printed on to 51 cards (one to each abbreviation), it is possible to make a circular chain of cards, so that the same letters are next to each other at the joins. (You are not allowed to reverse the letters in an abbreviation, i.e. invert a card).

      For example, here is a chain of 8 cards:

      IN:NV:VT:TN:NM:MO:OR:RI:[IN]

      How long is the longest circular chain of cards you can make?

      My solution follows…


      This Python program runs in 82ms. (Internal runtime is 29.7ms).

      Run: [ @replit ]

      from enigma import (group, item, Accumulator, join, printf)
      
      states = str.split(
        "AK AL AR AZ CA CO CT DC DE FL GA HI IA ID IL IN KS "
        "KY LA MA MD ME MI MN MO MS MT NC ND NE NH NJ NM NV "
        "NY OH OK OR PA RI SC SD TN TX UT VA VT WA WI WV WY"
      )
      
      # group states by first letter
      g = group(states, by=item(0), fn=set)
      
      # generate possible circular chains of states
      def solve(ss):
        # possible next letters
        xs = g.get(ss[-1][-1])
        if not xs: return
        # does the sequence form a chain?
        if len(ss) > 1 and ss[-1][-1] == ss[0][0]:
          yield ss
        # try to extend the sequence
        for x in xs:
          if not (x < ss[0] or x in ss):
            yield from solve(ss + [x])
      
      # find maximal chains starting with the alphabetically first state
      r = Accumulator(fn=max, collect=1)
      for s0 in states:
        for ss in solve([s0]):
          r.accumulate_data(len(ss), ss)
      
      # output solution
      printf("[max length = {r.value}]")
      for ss in r.data:
        printf("chain = [{ss}]", ss=join(ss, sep=","))
      

      Solution: The longest chain uses 21 cards.

      There are 56 possible chains of length 21. Here is one of them:

      AK:KS:SC:CO:OH:HI:IN:NM:MN:NC:CA:AR:RI:ID:DC:CT:TN:NV:VA:AL:LA:[AK]

      Like

    • Jim Olson's avatar

      Jim Olson 5:00 pm on 16 January 2023 Permalink | Reply

      Thanks for pointing out the Times ignorance of the number of states!

      Like

  • Unknown's avatar

    Jim Randell 9:12 am on 10 January 2023 Permalink | Reply
    Tags:   

    Teaser 2687: Creased 

    From The Sunday Times, 23rd March 2014 [link] [link]

    I took a rectangular piece of paper whose sides were whole numbers of centimetres — indeed the longer side was exactly three times the length of the shorter side. I folded the rectangle along a diagonal. I then took the folded piece and folded it again along its line of symmetry. Then I completely unfolded it to see that the two creases had divided the rectangle into two equal triangles and two equal quadrilaterals. In square centimetres the area of each triangle was a three-figure number, and the area of each quadrilateral was another three- figure number using the same three digits but in a different order.

    What was the area of each triangle?

    [teaser2687]

     
    • Jim Randell's avatar

      Jim Randell 9:14 am on 10 January 2023 Permalink | Reply

      If the dimensions of the original rectangle are x by 3x. Then it has an area of 3x².

      The result of the folds looks like this:

      X is in the centre of the rectangle (so 3x/2 from the left/right edges and x/2 from the top/bottom edges).

      And Y is vertically below X, so we have:

      OY = 3x/2
      XY = x/2
      OX = x√(5/2)

      The triangles OXY and XZY are similar. With the sides of OXY being 3× those of XZY.

      Hence:

      XZ = (x/3)√(5/2)

      And the area of triangle OXZ is given by:

      T = (1/2)(XZ)(OX)
      T = (1/2)(x/3)x(5/2)
      T = (5/12)x²

      And the area of the quadrilateral ABXZ is:

      Q = (3/2)x² − T
      Q = (13/12)x²

      The following Python program runs in 51ms. (Internal runtime is 99µs).

      Run: [ @replit ]

      from enigma import (irange, inf, nsplit, printf)
      
      # digits of a number, in order
      digits = lambda n: sorted(nsplit(n))
      
      # consider x values
      for x in irange(1, inf):
        x2 = x * x
        (T, t) = divmod(x2 * 5, 12)
        (Q, q) = divmod(x2 * 13, 12)
        # T and Q are 3 digit numbers, with no remainder
        if Q > 999: break
        if t > 0 or q > 0 or T < 100: continue
        # do T and Q use the same digits?
        if digits(T) == digits(Q):
          printf("x={x}: T={T} Q={Q}")
      

      Solution: The area of each triangle is: 135 cm².

      And the area of the quadrilaterals is: 351 cm².

      The original rectangle had dimensions: 18 cm × 54 cm. (Area = 972 = 2 × (135 + 351)).

      Like

    • GeoffR's avatar

      GeoffR 1:22 pm on 10 January 2023 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";
      
      % using Jim's analysis and notations
      var 1..50:x; var 1..50:OX; var 1..50:OY;
      var 1..50:XZ; var 100..250:T; var 100..500:Q;
      
      constraint 2 * OX == 3 * x /\ 2 * OY == x;
      constraint 12 * T == 5 * x * x;
      constraint 12 * Q == 13 * x * x;
      
      % Digits in triangular area (a, b, c)
      var 1..9:a; var 0..9:b; var 1..9:c;
      constraint a == T div 100 /\ b == T div 10 mod 10 /\ c == T mod 10;
      
      % Digits in quadrilateral area (d, e, f)
      var 1..9:d; var 0..9:e; var 0..9:f;
      constraint d == Q div 100 /\ e == Q div 10 mod 10 /\ f == Q mod 10;
      
      % Digits in triangular area = Digits in quadrilateral area
      constraint {a, b, c} == {d, e, f};
      
      solve satisfy;
      
      output ["Triangle area = " ++ show(T) ++ " sq cm"
      ++ "\n" ++ "Quadrilateral area = " ++ show(Q) ++ " sq cm"];
      
      % Triangle area = 135 sq cm
      % Quadrilateral area = 351 sq cm
      % ----------
      % ==========
      
      
      

      Like

      • Jim Randell's avatar

        Jim Randell 9:40 am on 11 January 2023 Permalink | Reply

        @Geoff: I think the digit constraint at line 21 needs to be a bit stronger. Two numbers that had repeated digits could pass the test without being reorderings of the same collection of digits (e.g. 141 and 414).

        Like

        • GeoffR's avatar

          GeoffR 10:03 am on 11 January 2023 Permalink | Reply

          @Jim:
          Maybe like this?

          % Digits in triangular area = Digits in quadrilateral area
          constraint {a, b, c} == {d, e, f} /\ a != d /\ b != e /\ c != f
          /\ all_different([a, b, c]);
          

          Like

        • Jim Randell's avatar

          Jim Randell 11:22 am on 11 January 2023 Permalink | Reply

          I think something like this would be more appropriate:

          constraint sort([a, b, c]) = sort([d, e, f]);
          

          Like

    • Hugh Casement's avatar

      Hugh Casement 7:46 am on 11 January 2023 Permalink | Reply

      As triangles OXY and XZY are similar, YZ = x/6, which gives us another way to calculate T
      as half base OZ times height XY, without any square roots.

      I notice that whenever two integers in the ratio 5:13 have the same digit sum,
      that is 9 or a multiple of 9; e.g. 45:117, 90:234, 270:702.
      The last of those would be a further solution, wouldn’t it?

      Like

  • Unknown's avatar

    Jim Randell 10:55 am on 3 January 2023 Permalink | Reply
    Tags: ,   

    Teaser 2702: Problemblem 

    From The Sunday Times, 6th July 2014 [link] [link]

    Every Sunday customers in our pub try to solve the current Teaser, so Pat the barman has designed an appropriate pub logo. This is a small rectangular flag divided into three smaller rectangles, coloured red, green and blue. Their sides are all whole numbers of centimetres, the area of the green rectangle is twice the area of the red rectangle, and the perimeter of the red rectangle is twice the perimeter of the green rectangle. Furthermore, the area of the flag is a three-figure number of square centimetres, the same as the area of the blue rectangle but with the three digits in the reverse order.

    What is the area of the flag?

    [teaser2702]

     
    • Jim Randell's avatar

      Jim Randell 10:56 am on 3 January 2023 Permalink | Reply

      This Python program generates candidate areas for the red, green and blue rectangles. It then looks for appropriate dimensions that satisfy the remaining conditions, and allow them to fit together as specified.

      It runs in 60ms. (Internal runtime is 7.3ms).

      Run: [ @replit ]

      from enigma import (irange, nrev, div, divisors_pairs, cproduct, ordered, printf)
      
      # fit the rectangles (x1, y1), (x2, y2) and a rectangle area A together
      def fit(x1, y1, x2, y2, A):
        for z1 in {x1, y1}:
          # can we match a side?
          if z1 in {x2, y2}:
            (x, y) = (z1, div(A, z1))
            if y is not None:
              yield ordered(x, y)
          # can we join sides?
          for z2 in {x2, y2}:
            y = (x1 + y1 - z1) - (x2 + y2 - z2)
            if y > 0:
              if z2 * y == A:
                yield ordered(z2, y)
            elif y < 0:
              y = -y
              if z1 * y == A:
                yield ordered(z1, y)
      
      # consider the area of the flag, it is a 3-digit number
      for A in irange(100, 999):
        # and the area of blue is the reverse of this
        B = nrev(A)
        if B < 100 or not (B < A): continue
        # the area of red and green are 1/3 and 2/3 of what is left
        R = div(A - B, 3)
        if R is None: continue
        G = 2 * R
      
        # find dimensions for red and green, such that red has twice the perimeter of green
        for ((rx, ry), (gx, gy)) in cproduct(divisors_pairs(v) for v in (R, G)):
          if not (rx + ry == 2 * (gx + gy)): continue
      
          # find dimensions of blue that fits to make a rectangle
          for (bx, by) in fit(rx, ry, gx, gy, B):
            # output solution
            printf("A={A} [R={R} G={G} B={B}]", R=(rx, ry), G=(gx, gy), B=(bx, by))
      

      Solution: The area of the flag is: 231 sq cm.

      The flag is a 7×33 rectangle, as shown below:

      The red rectangle is: 1×33. The green rectangle is 6×11. The blue rectangle is 6×22.

      (Dimensions in cm).


      We have sometime come across claims that a phrase such as “a whole number of pounds” (or similar – see Teaser 2869, Teaser 2692) necessarily implies a value must be at least 2 (although I do not accept this argument myself). But this puzzle uses “a whole number of centimetres” to refer to a value of 1, and without allowing this value there would be no solution.

      Like

    • GeoffR's avatar

      GeoffR 3:28 pm on 3 January 2023 Permalink | Reply

      % A Solution in MiniZinc - same rectangle arrangement
      % Red = A * B, Green = C * D, Blue = C  * E, where B = D + E
      include "globals.mzn";
      
      % Assumed Rectangle/Area dimension ranges
      var 1..25:A; var 1..50:B;
      var 1..25:C; var 1..25:D; var 1..25:E;
      
      var 10..999:flag_area;
      var 1..999:red_area; var 1..999:green_area; var 1..999:blue_area;
      var 4..200:red_perim; var 4..200:green_perim;
      
      % Red length = Green length + Blue length
      constraint B == D + E;
      
      % Digits (x,y,z) for 3-digit flag area
      var 1..9:x; var 0..9:y;  var 1..9:z; 
      
      % Find three digits of flag area
      constraint x == flag_area div 100 /\ y == flag_area div 10 mod 10
      /\ z == flag_area mod 10;
      
      % Flag area digits are reversed for the blue area
      constraint blue_area = C * E /\ blue_area == 100*z + 10*y + x; 
      constraint green_area = C * D /\ red_area = A * B;
      constraint red_perim = 2 * (A + B);
      constraint green_perim == 2 * (C + D);
      
      % Area/perimeter relationships
      constraint green_area = 2 * red_area;
      constraint red_perim = 2 * green_perim;
      constraint flag_area = red_area + blue_area + green_area;
      
      solve satisfy;
      
      output [ "Flag area = " ++ show(flag_area) ++ " sq. cm.," 
      ++ " Red area = " ++ show(red_area) ++ " sq. cm." 
      ++ "\n" ++ "Green area = " ++ show(green_area) ++ " sq. cm.,"
      ++ " Blue area = " ++ show(blue_area) ++ " sq. cm."  ];
      
      % Flag area = 231 sq. cm., Red area = 33 sq. cm.
      % Green area = 66 sq. cm., Blue area = 132 sq. cm.
      % ----------
      % ==========
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 8:50 am on 22 December 2022 Permalink | Reply
    Tags:   

    Teaser 2693: Let the dog see the rabbit 

    From The Sunday Times, 4th May 2014 [link] [link]

    Each of Messrs Burrows, Cook, Field, Skinner and Warren has a pet dog, and each of the men’s wives has a pet rabbit. Each dog bit one of the rabbits, with no two dogs biting the same rabbit. Mrs Warren’s rabbit was bitten by Mr Skinner’s dog. Mr Warren’s dog bit the rabbit owned by the wife of the owner of the dog that bit Mrs Field’s rabbit. Mrs Burrows’ rabbit was bitten by the dog owned by the husband of the lady whose rabbit was bitten by the dog belonging to the husband of the lady whose rabbit was bitten by the dog belonging to Mr Cook.

    Whose dog bit Mrs Skinner’s rabbit, and whose rabbit did Mr Field’s dog bite?

    There are now 800 Teaser puzzles available on the site.

    [teaser2693]

     
    • Jim Randell's avatar

      Jim Randell 8:53 am on 22 December 2022 Permalink | Reply

      Each surname has a dog and a rabbit, so we can just attach the surnames directly to the animals.

      This Python program runs in 50ms. (Internal runtime is 180µs).

      Run: [ @replit ]

      from enigma import (subsets, printf)
      
      # label the surnames
      names = (B, C, F, S, W) = (0, 1, 2, 3, 4)
      
      # choose an ordering of the names for the rabbits
      # r[X] == Y  ->  "dog X bit rabbit Y"
      for r in subsets(names, size=len, select="P"):
      
        # "rabbit W was bitten by dog S"
        if not (r[S] == W): continue
      
        # "dog W bit rabbit of family of dog that bit rabbit F"
        if not (r[r[W]] == F): continue
      
        # "rabbit B was bitten by the dog of family whose rabbit was bitten by the
        # dog of family whose rabbit was bitten by dog C"
        if not (r[r[r[C]]] == B): continue
      
        # output solution (dog -> rabbit)
        name = "BCFSW"
        for (x, y) in zip(names, r):
          printf("dog {x} bit rabbit {y}", x=name[x], y=name[y])
        printf()
      

      Solution: Cook’s dog bit Skinner’s rabbit. Field’s dog bit Cook’s rabbit.

      The full solution is:

      dog B bit rabbit F
      dog C bit rabbit S
      dog F bit rabbit C
      dog S bit rabbit W
      dog W bit rabbit B

      Like

  • Unknown's avatar

    Jim Randell 9:56 am on 15 December 2022 Permalink | Reply
    Tags: ,   

    Teaser 2686: Good innings 

    From The Sunday Times, 16th March 2014 [link] [link]

    Tomorrow is St Patrick’s Day, so Pat will go on his usual tour of inns. Last year each inn had the same admission charge (made up of a two-figure number of pounds plus a two-figure number of pence surcharge). This four-figure total of pence happened to be the same as the four-figure number of pence Pat started the evening with, except that the order of the digits was reversed. In the first inn he spent one pound less than a third of what he had left after paying admission. In the second inn he also spent one pound less than a third of what he came in with after paying admission. That left him just enough to get into the third inn.

    How much was that?

    [teaser2686]

     
    • Jim Randell's avatar

      Jim Randell 9:57 am on 15 December 2022 Permalink | Reply

      The entry fee is a 4-digit number of pence, and Pat’s initial funds are the reverse of this number (also a 4-digit number).

      As Pat pays 3 entry fees, each one cannot be more than £33.33, so we don’t need to check entry fees more than that.

      Run: [ @replit ]

      from enigma import (irange, nreverse, as_int, ediv, catch, printf)
      
      # check for viable spending pattern
      def check(entry):
        # starting amount is the reverse of the entry fee
        funds = start = nreverse(entry)
        # first pub
        funds = as_int(funds - entry, "+")
        spend1 = as_int(ediv(funds, 3) - 100, "+")
        funds = as_int(funds - spend1, "+")
        # second pub
        funds = as_int(funds - entry, "+")
        spend2 = as_int(ediv(funds, 3) - 100, "+")
        funds = as_int(funds - spend2, "+")
        # third pub
        funds = as_int(funds - entry, "0")
        # output solution
        printf("entry = {entry}; start = {start}; spend1 = {spend1}; spend2 = {spend2}")
      
      # consider 4-digit entry fees
      for entry in irange(1000, 3333):
        catch(check, entry)
      

      Solution: The entry fee was: £14.56.

      So Pat’s finances go:

      start = £65.41
      pub 1 entry = £14.56 → £50.85
      pub 1 spend = £15.95 → £34.90
      pub 2 entry = £14.56 → £20.34
      pub 2 spend = £5.78 → £14.56
      pub 3 entry = £14.56 → £0.00

      Like

  • Unknown's avatar

    Jim Randell 9:19 am on 8 December 2022 Permalink | Reply
    Tags: ,   

    Teaser 2694: Impaired 

    From The Sunday Times, 11th May 2014 [link] [link]

    Pat was given a rod of length 40 centimetres and he cut it into six pieces, each piece being a whole number of centimetres long, and with the longest piece twice as long as one of the other pieces. Then he took two of the pieces and wrote down their total length. He did this for every possible set of two pieces and he never got the same total more than once. However, when he started again and repeated the process but with sets of three pieces, one of the totals was repeated.

    What (in increasing order) were the lengths of his pieces?

    [teaser2694]

     
    • Jim Randell's avatar

      Jim Randell 9:20 am on 8 December 2022 Permalink | Reply

      Each of the pieces must be of a different length. Otherwise there will be duplication amongst the 2-subsets.

      This Python program runs in 52ms. (Internal runtime is 533µs).

      Run: [ @replit ]

      from enigma import (
        irange, inf, decompose, subsets, seq_all_different as all_different, printf
      )
      
      # totals of k-subsets of ps
      subs = lambda ps, k: (sum(ss) for ss in subsets(ps, size=k))
      
      # there are pieces of length x and 2x
      for x in irange(1, inf):
        # remaining length (must allow 4 more pieces)
        r = 40 - 3 * x
        if r < 10: break
        # cut the remaining length into 4 pieces
        for ps in decompose(r, 4, increasing=1, sep=1, min_v=1, max_v=2 * x - 1):
          ps += (x, 2 * x)
      
          # all 2-subsets have different totals
          if not all_different(subs(ps, 2)): continue
      
          # but there are exactly 2 3-subsets that have the same total
          ss = list(subs(ps, 3))
          if len(set(ss)) + 1 != len(ss): continue
      
          # output solution
          printf("ps = {ps}", ps=sorted(ps))
      

      Solution: The lengths of the pieces are (cm): 1, 4, 5, 7, 9, 14.

      This gives two 3-subsets that give a total of 20:

      1 + 5 + 14 = 20
      4 + 7 + 9 = 20

      The set (1, 3, 4, 5, 9, 18) gives no repeated totals for 2-subsets or 3-subsets.

      Like

    • GeoffR's avatar

      GeoffR 8:01 pm on 8 December 2022 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";
      
      % six lengths of rod - assume max single length = 30cm.
      var 1..30:A; var 1..30:B; var 1..30:C; 
      var 1..30:D; var 1..30:E; var 1..30:F;
      
      constraint all_different([A, B, C, D, E, F]);
      
      % put the rods in increasing size order
      constraint increasing([A, B, C, D, E, F]);
      
      % initial rod is 40 cm long
      constraint A + B + C + D + E + F == 40;
      
      % the longest rod is twice as long as one of the other rods
      constraint F == 2*E \/ F == 2*D \/ F == 2*C \/ F == 2*B \/ F == 2*A;   
      
      % sub-totals for 2 rods (15 no.)-  UB = 30 + 29 = 59
      var 3..59: t1; var 3..59: t2; var 3..59: t3; var 3..59: t4; var 3..59: t5;
      var 3..59: t6; var 3..59: t7; var 3..59: t8; var 3..59: t9; var 3..59: t10;
      var 3..59: t11; var 3..59: t12; var 3..59: t13; var 3..59: t14; var 3..59: t15;
      
      % All two rod sums
      constraint t1 = A + B /\ t2 = A + C /\ t3 = A + D /\ t4 = A + E
      /\ t5 = A + F /\ t6 = B + C /\ t7 = B + D /\ t8 = B + E 
      /\ t9 = B + F /\ t10 = C + D /\ t11 = C + E /\ t12 = C + F
      /\ t13 = D + E /\ t14 = D + F /\ t15 = E + F;
      
      % All 2 rod sums are different
      constraint all_different([t1, t2, t3, t4, t5, t6, t7, t8, t9, t10,
      t11, t12, t13, t14, t15]);
      
      % sub-totals for 3 rods (20 no.)-  UB = 30+29+28 = 87
      var 6..87:T1; var 6..87:T2; var 6..87:T3; var 6..87:T4; 
      var 6..87:T5; var 6..87:T6; var 6..87:T7; var 6..87:T8;
      var 6..87:T9; var 6..87:T10; var 6..87:T11; var 6..87:T12;
      var 6..87:T13; var 6..87:T14; var 6..87:T15; var 6..87:T16; 
      var 6..87:T17; var 6..87:T18; var 6..87:T19; var 6..87:T20;
      
      % All 3-digit sums - one of sums is duplicated - see output
      constraint T1 = A+B+C /\ T2 = A+B+D /\ T3 = A+B+E /\ T4 = A+B+F
      /\ T5 = A+C+D /\  T6 = A+C+E /\ T7 = A+C+F /\ T8 = A+D+E
      /\ T9 = A+D+F /\ T10 = A+E+F /\ T11 = B+C+D /\ T12 = B+C+E
      /\ T13 = B+C+F /\ T14 = B+D+E /\ T15 = B+D+F /\ T16 = B+E+F
      /\ T17 = C+D+E /\ T18 = C+D+F /\ T19 = C+E+F /\ T20 = D+E+F;
      
      % array of 3-digit sums
      array[1..20] of var 6..87: y; 
      constraint y = [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
      T11, T12, T13, T14, T15, T16 ,T17, T18, T19, T20];
      
      % array of 2-digit sums
      array[1..15] of var 3..59: x; 
      constraint x = [t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11,
      t12, t13, t14, t15];
      
      solve satisfy;
      
      output[" Six Rod Pieces are [A,B,C,D,E,F] = " ++ show([A,B,C,D,E,F]) 
      ++ " \n 2-rod length sums: " ++ show(x)
      ++ " \n 3-rod length sums: " ++ show(y)];
      
      % Six Rod Pieces are [A,B,C,D,E,F] = [1, 4, 5, 7, 9, 14]  << ANSWER
      %  2-rod length sums: [5, 6, 8, 10, 15, 9, 11, 13, 18, 12, 14, 19, 16, 21, 23] 
      %  3-rod length sums: [10, 12, 14, 19, 13, 15, 20, 17, 22, 24, 16,
      %  18, 23, 20, 25, 27, 21, 26, 28, 30]
      % ----------
      %  - INVALID, No duplicated 3 rod sums
      %  Six Rod Pieces are [A,B,C,D,E,F] = [1, 3, 4, 5, 9, 18] 
      %  2-rod length sums: [4, 5, 6, 10, 19, 7, 8, 12, 21, 9, 13, 22, 14, 23, 27] 
      %  3-rod length sums: [8, 9, 13, 22, 10, 14, 23, 15, 24, 28, 12, 16,
      %  25, 17, 26, 30, 18, 27, 31, 32]
      % ----------
      % ==========
      
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 10:42 am on 6 December 2022 Permalink | Reply
    Tags:   

    Teaser 2690: Leaving present 

    From The Sunday Times, 13th April 2014 [link] [link]

    When maths teacher Adam Up reached the age of 65, he asked his colleagues for some spring bulbs as a leaving present. So they gave him some packs of bulbs with, appropriately enough, each pack containing 65 bulbs.

    Adam planted all the bulbs in clumps of different sizes, the number of bulbs in each clump being a prime number. Furthermore, these prime numbers overall used each of the ten digits exactly once. Had he been given any fewer packs this would have been impossible.

    How many bulbs were there in the smallest and largest clumps?

    [teaser2690]

     
    • Jim Randell's avatar

      Jim Randell 10:42 am on 6 December 2022 Permalink | Reply

      I implemented a multiset exact cover algorithm [[ mcover() ]] when I revisited Enigma 1712. And the same function can be used to solve this puzzle.

      As we are looking for the smallest number of packs we can start by considering primes up to 65, to see if the problem can be solved using a single pack, and if not we can then add primes between 66 and 130 into the mix, and so on until we find a number of packs that provides solutions.

      The following Python program runs in 56ms. (Internal run time is 3.7ms).

      Run: [ @replit ]

      from enigma import (irange, primes, inf, nsplit, multiset, mcover, printf)
      
      # incremental multiple
      N = 65
      
      # target digit contents (each digit once)
      tgt = multiset.from_seq(irange(0, 9), count=1)
      
      # start with 0 multiples
      k = 0
      m = dict()  # map primes to digit content
      for p in primes.irange(2, inf):
        # have we finished a chunk?
        k_ = p // N
        if k_ > k:
          k = k_
          kN = k * N
          # look for covers using this collection of primes
          n = 0
          for ss in mcover(m, tgt, (lambda ss: sum(ss) > kN)):
            # check for required sum
            if sum(ss) == kN:
              # output solution
              printf("{ss} -> {k} * {N}", ss=sorted(ss))
              n += 1
          # are we done?
          if n > 0:
            printf("[{n} solutions]")
            break
      
        # add primes that are subsets of the target into the list
        ds = multiset.from_seq(nsplit(p))
        if ds.issubset(tgt):
          m[p] = ds
      

      Solution: The smallest clump had 5 bulbs. The largest clump had 401 bulbs.

      There are 2 ways to achieve the solution with 9 packs of 65 bulbs (= 585 bulbs in total):

      5 + 29 + 67 + 83 + 401 = 585
      5 + 23 + 67 + 89 + 401 = 585

      Like

    • GeoffR's avatar

      GeoffR 7:02 pm on 6 December 2022 Permalink | Reply

      The only way I could find a solution in MiniZinc was to assume the ten digit pattern of the primes i.e. 1,2,2,2,3. There has to be at least one 3-digit prime with zero as the middle digit.

      % A Solution in MiniZinc
      include "globals.mzn";
      
      % Using a 1,2,2,2,3 digit prime pattern
      
      var 1..9:A; var 1..9:B; var 1..9:C; var 1..9:D;
      var 1..9:E; var 1..9:F; var 1..9:G; var 1..9:H;
      var 0..9:I; var 1..9:J;
      
      var 10..99:BC = 10*B + C;
      var 10..99:DE = 10*D + E;
      var 10..99:FG = 10*F + G;
      var 100..999:HIJ = 100*H + 10*I + J;
      
      predicate is_prime(var int: x) = 
      x > 1 /\ forall(i in 2..1 + ceil(sqrt(int2float(ub(x)))))
      ((i < x) -> (x mod i > 0));
      
      constraint sum([is_prime(A), is_prime(BC), is_prime(DE), 
      is_prime(FG), is_prime(HIJ)]) == 5;
      
      constraint card( {A,B,C,D,E,F,G,H,I,J}) == 10;
      % There are 65 bulbs in each pack
      constraint (A + BC + DE + FG + HIJ) mod 65 == 0;
      
      constraint increasing([A,BC,DE,FG,HIJ]);
      
      solve satisfy;
      
      output ["Smallest clump = " ++ show(A) ++ 
      " , Largest clump = " ++ show(HIJ) ++
      "\n" ++ "[A,BC,DE,FG,HIJ] = " ++ show([A,BC,DE,FG,HIJ] )];
      
      % Smallest clump = 5 , Largest clump = 401
      % [A,BC,DE,FG,HIJ] = [5, 29, 67, 83, 401]
      % ----------
      % Smallest clump = 5 , Largest clump = 401
      % [A,BC,DE,FG,HIJ] = [5, 23, 67, 89, 401]
      % ----------
      % ==========
      
      
      

      Out of interest I then adapted the program to check a different prime digit pattern, which was 2,2,3,3 for the ten digits. All the answers used 18 packs of 65 bulbs, exactly double the original solution using 9 packs of 65 bulbs = 585

      % [AB,CD,EFG,HIJ] for different 10-digits pattern
      % [AB,CD,EFG,HIJ] = [43, 61, 257, 809]
      % [AB,CD,EFG,HIJ] = [53, 89, 421, 607]
      % [AB,CD,EFG,HIJ] = [59, 83, 421, 607]
      % [AB,CD,EFG,HIJ] = [53, 67, 241, 809]
      % [AB,CD,EFG,HIJ] = [43, 67, 251, 809]
      % [AB,CD,EFG,HIJ] = [29, 83, 457, 601]
      % [AB,CD,EFG,HIJ] = [23, 89, 457, 601]
      % [AB,CD,EFG,HIJ] = [29, 53, 487, 601]
      % [AB,CD,EFG,HIJ] = [23, 59, 487, 601]
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 8:58 am on 1 December 2022 Permalink | Reply
    Tags:   

    Teaser 2689: The right choice 

    From The Sunday Times, 6th April 2014 [link] [link]

    I am organising a tombola for the fete. From a large sheet of card (identical on both sides) I have cut out a lot of triangles of equal area. All of their angles are whole numbers of degrees and no angle exceeds ninety degrees. I have included all possible triangles with those properties and no two of them are identical. At the tombola entrants will pick a triangle at random and they will win if their triangle has a right-angle. The chances of winning turn out to be one in a certain whole number.

    What is that whole number?

    [teaser2689]

     
    • Jim Randell's avatar

      Jim Randell 8:59 am on 1 December 2022 Permalink | Reply

      Once we have chosen the three angles of the triangle (each an integer between 1° and 90°, that together sum 180°), we can form a triangle with the required area by scaling it appropriately.

      This Python program counts the number of possible triangles and the number of them that are right angled.

      It runs in 53ms. (Internal runtime is 1.0ms).

      Run: [ @replit ]

      from enigma import (decompose, fraction, printf)
      
      # generate possible triangles
      triangles = lambda: decompose(180, 3, increasing=1, sep=0, min_v=1, max_v=90)
      
      # count:
      # t = total number of triangles
      # r = number with a right angle
      r = t = 0
      for (a, b, c) in triangles():
        t += 1
        if c == 90: r += 1
      
      # output solution
      (p, q) = fraction(r, t)
      printf("P(win) = {r}/{t} = {p}/{q}")
      

      Solution: The chance of winning is 1/16.

      There are 720 triangles, and 45 of them are right angled.

      I think it would be annoying to choose a triangle with an 89° angle.

      Like

  • Unknown's avatar

    Jim Randell 8:28 am on 29 November 2022 Permalink | Reply
    Tags:   

    Teaser 2685: Not the Gold Cup 

    From The Sunday Times, 9th March 2014 [link] [link]

    Five horses took part in a race, but they all failed to finish, one falling at each of the first five fences. Dave (riding Egg Nog) lasted longer than Bill whose horse fell at the second fence; Big Gun fell at the third, and the jockey wearing mauve lasted the longest. Long Gone lasted longer than the horse ridden by the jockey in yellow, Chris’s horse fell one fence later than the horse ridden by the jockey in green, but Fred and his friend (the jockey in blue) did not fall at adjacent fences. Nig Nag was ridden by Wally and Dragon’s jockey wore red.

    Who was the jockey in yellow, and which horse did he ride?

    [teaser2685]

     
    • Jim Randell's avatar

      Jim Randell 8:28 am on 29 November 2022 Permalink | Reply

      I used the [[ SubstitutedExpression ]] solver from the enigma.py library to assign the fence values (1-5) to the 3 groups of jockeys, horses and colours.

      The following run file executes in 66ms. (Internal runtime of the generated program is 94µs).

      Run: [ @replit ]

      #! python3 -m enigma -rr
      
      # assign fence numbers (1-5) to the following groups:
      #
      #  jockeys = A (Wally), B (Bob), C (Chris), D (Dave), E (Fred)
      #  horses  = F (Egg Nog), G (Big Gun), H (Long Gone), I (Nig Nag), J (Dragon)
      #  colours = K (mauve), L (yellow), M (green), N (blue), P (red)
      
      SubstitutedExpression
      
      --base="6"
      --digits="1-5"
      --distinct="ABCDE,FGHIJ,KLMNP"
      --template="(A B C D E) (F G H I J) (K L M N P)"
      --solution=""
      
      # "Dave (D) riding Egg Nog (F) lasted longer than Bill (B) who fell at the 2nd fence"
      "D = F"
      "D > B"
      "2 = B"
      
      # "Big Gun (G) fell at the 3rd"
      "3 = G"
      
      # "mauve (K) lasted the longest"
      "5 = K"
      
      # "Long Gone (H) lasted longer than yellow (L)
      "H > L"
      
      # "Chris's (C's) horse fell one fence later than the horse ridden by green (M)"
      "M + 1 = C"
      
      # "Fred (E) and his friend blue (N) did not fall at adjacent fences"
      "abs(E - N) > 1"
      
      # "Nig Nag (I) was ridden by Wally (A)"
      "I = A"
      
      # "Dragon's (J's) jockey wore red"
      "J = P"
      

      We can wrap this in Python code to format the solution in a more friendly form:

      Run: [ @replit ]

      from enigma import (SubstitutedExpression, group, printf)
      
      # load the run file
      p = SubstitutedExpression.from_file("teaser2685.run")
      
      # map symbols to jockey, horse, colour names
      name = dict(
        A="Wally", B="Bob", C="Chris", D="Dave", E="Fred",
        F="Egg Nog", G="Big Gun", H="Long Gone", I="Nig Nag", J="Dragon",
        K="mauve", L="yellow", M="green", N="blue", P="red",
      )
      
      # solve the puzzle
      for s in p.solve(verbose=0):
        # group symbols by value
        d = group(s.keys(), by=s.get)
        # output solution for each fence
        for k in sorted(d.keys()):
          # extract jockey, horse, colour
          (j, h, c) = (name[s] for s in sorted(d[k]))
          printf("{k}: {j} ({c}) on {h}")
        printf()
      

      Solution: Fred was in yellow, riding Big Gun.

      The full solution is:

      1st fence: Wally (blue) on Nig Nag
      2nd fence: Bob (red) on Dragon
      3rd fence: Fred (yellow) on Big Gun
      4th fence: Dave (green) on Egg Nog
      5th fence: Chris (mauve) on Long Gone

      Like

  • Unknown's avatar

    Jim Randell 9:04 am on 22 November 2022 Permalink | Reply
    Tags:   

    Teaser 2688: Mother’s Day 

    From The Sunday Times, 30th March 2014 [link] [link]

    Today we are having a family get-together to celebrate Mother’s Day. My maternal grandmother, my mother and I have each written down our date of birth in the form “ddmmyy”. This gives us three six-digit numbers and, surprisingly, both of the ladies’ numbers are multiples of mine. Furthermore, all of the digits from 0 to 9 occur somewhere in the three six-digit numbers.

    What is my mother’s six-digit date of birth?

    [teaser2688]

     
    • Jim Randell's avatar

      Jim Randell 9:05 am on 22 November 2022 Permalink | Reply

      At first I found many possible solutions to this puzzle.

      But if we require that the 6-digit numbers formed from the date cannot have a leading zero, then this narrows down the solution space considerably (and essentially restricts the three dates to the form 10xxxx, 20yyyy, 30zzzz, and the multiples being 1, 2, 3).

      This Python program runs in 129ms.

      Run: [ @replit ]

      from datetime import (date, timedelta)
      from enigma import (
        fdiv, inc, repeat, nconcat, nsplit, catch,
        subsets, append, tuples, union, join, printf
      )
      
      # extract date as a 6-digit number
      def number(d):
        if d.day < 10: return None
        return nconcat(d.day, d.month, d.year % 100, base=100)
      
      # check viable generation gap, a -> b
      def gap(a, b):
        y = fdiv((b - a).days, 365.2422)
        return not (y < 16 or y > 50)
      
      # consider dates for the setters birthdate
      for d in repeat(inc(timedelta(days=-1)), date(2014, 3, 30)):
        if d.year < 1922: break
        # construct the number "ddmmyy"
        n = number(d)
        if n is None: continue
        # look for proper multiples that also give a valid date
        mn = n
        ds = list()
        while True:
          mn += n
          if mn > 311299: break
          (dd, mm, yy) = nsplit(mn, base=100)
          for y in (1900 + yy, 1800 + yy):
            if y < 1892: continue
            md = catch(date, y, mm, dd)
            if md is None or number(d) is None: continue
            ds.append(md)
      
        # look for a set of 3 plausible ages
        for ss in subsets(sorted(ds), size=2):
          ss = append(ss, d)
          if not all(gap(a, b) for (a, b) in tuples(ss, 2)): continue
          # check all digits are used
          if len(union(nsplit(number(d)) for d in ss)) < 10: continue
          # output dates
          printf("{ss}", ss=join(ss, sep=" -> "))
      

      The program works backwards from 2014 to 1922 looking for sets of 3 dates that make a plausible set of birthdates for the three generations.

      It finds 2 possible situations, as below (ages shown are on the date the puzzle was published (2014-03-30)):

      Grandmother = 1919-08-30 (age = 94.6y)
      Mother = 1946-05-20 (age = 67.9y)
      Setter = 1973-02-10 (age = 41.1y)
      gap = 26.7y
      100273 × 2 = 200546
      100273 × 3 = 300819

      Grandmother = 1892-07-30 (age = 121.7y)
      Mother = 1928-05-20 (age = 85.9y)
      Setter = 1964-02-10 (age = 50.1y)
      gap = 35.7y
      100264 × 2 = 200528
      100264 × 3 = 300792

      The second of these is only just plausible, so presumably the first provides the required answer. (I would have preferred the puzzle eliminated one of these solutions by an explicit condition).

      Solution: The mother’s date of birth is: 200546 (i.e. 20th May 1946).

      To see solutions where the 6-digit number formed from the date is permitted to have a leading zero, the check at line 9 can be removed. In this case the program finds 115 solutions.

      Like

  • Unknown's avatar

    Jim Randell 8:49 am on 17 November 2022 Permalink | Reply
    Tags:   

    Teaser 2680: Yesterday 

    From The Sunday Times, 2nd February 2014 [link] [link]

    In a new design of mobile phone each of the number buttons 1 to 9 is associated with 2 or 3 letters of the alphabet, but not in alphabetical order (and there are no letters on any other buttons). For example: M, T and U are on the same button. Predictive software chooses letters for you as you type. The numbers to type for SUNDAY, TIMES and TEASER are all multiples of 495.

    What number should I type to make SATURDAY?

    [teaser2680]

     
    • Jim Randell's avatar

      Jim Randell 8:52 am on 17 November 2022 Permalink | Reply

      We can solve this puzzle using the [[ SubstitutedExpression ]] solver from the enigma.py library.

      The following run file executes in 67ms. (Internal runtime of the generated program is 1.8ms).

      Run: [ @replit ]

      #! python3 -m enigma -rr
      
      SubstitutedExpression
      
      --digits="1-9"
      --distinct=""
      
      # SUNDAY, TIMES, TEASER are all multiples of 495
      "SUNDAY % 495 = 0"
      "TIMES % 495 = 0"
      "TEASER % 495 = 0"
      
      # M, T, U have the same value
      "M = T"
      "T = U"
      
      # no digit appears more than 3 times
      "all(v < 4 for v in multiset.from_seq([A, D, E, I, M, N, R, S, T, U, Y]).values())"
      
      --answer="SATURDAY"
      --template="SUNDAY TIMES TEASER SATURDAY"
      

      Solution: To type SATURDAY use the following keys: 58225185.

      The letters we are given are assigned to the following keys:

      1: D I
      2: M T U
      5: R S Y
      6: N
      8: A E

      So we have:

      SUNDAY = 526185 = 495 × 1063
      TIMES = 21285 = 495 × 43
      TEASER = 288585 = 495 × 583

      Like

    • GeoffR's avatar

      GeoffR 12:27 pm on 17 November 2022 Permalink | Reply

      # last digit of TIMES, SUNDAY, TEASER
      Y = S = R = 5
      
      digits = set(range(1, 10)).difference({5})
      
      for T in digits:
        M = U = T  # stated condition
        
        # Digits for I and E in TIMES
        for I in digits:
          for E in digits:
            TIMES = 10000*T + 1000*I + 100*M + 10*E + S
            if not (TIMES % 495 == 0):continue
            
            # Add Digit A for TEASER
            for A in digits:
              TEASER = 100000*T + 10000*E + 1000*A + 100*S + 10*E + R
              if not (TEASER % 495 == 0):continue
              
              # Add Digits N and D for SUNDAY
              for N in digits:
                for D in digits:
                  SUNDAY = 100000*S + 10000*U + 1000*N + 100*D + 10*A + Y
                  if not (SUNDAY % 495 == 0):continue
                  
                  print(f"Keys to press for SATURDAY are : ")
                  print(f"{S},{A},{T},{U},{R},{D},{A},{Y}")
                  print(f"SUNDAY = {SUNDAY}, TIMES={TIMES}, TEASER={TEASER}")
                  
      # Keys to press for SATURDAY are : 5,8,2,2,5,1,8,5
      # SUNDAY = 526185, TIMES=21285, TEASER=288585
      
      

      Like

    • GeoffR's avatar

      GeoffR 1:30 pm on 17 November 2022 Permalink | Reply

      This snippet needs to be added to the output to show no more than three digits were associated with
      each button.

      Digits used with each button as follows:

      [A,D,E,I,M,N,R,S,T,U,Y =
      [8,1,8,1,2,6,5,5,2,2,5]

      Like

  • Unknown's avatar

    Jim Randell 8:40 am on 10 November 2022 Permalink | Reply
    Tags:   

    Teaser 2611: Simple arithmetic 

    From The Sunday Times, 7th October 2012 [link] [link]

    George and Martha are teaching their great-grandchildren some simple arithmetic. “If you add two thirties to four tens you get a hundred”, George was saying, and he wrote it like this:

    “Strangely”, added Martha, there are nine different letters there, and if you allow each letter to stand for a different digit, there is a unique sum which works”.

    Which digit would be missing?

    [teaser2611]

     
    • Jim Randell's avatar

      Jim Randell 8:40 am on 10 November 2022 Permalink | Reply

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

      The following run file executes in 58ms. (Internal runtime is 4.74ms).

      Run: [ @replit ]

      from enigma import (SubstitutedExpression, irange, diff, join, printf)
      
      # construct the alphametic sum
      p = SubstitutedExpression.split_sum(
        ["THIRTY"] * 2 + ["TEN"] * 4, "HUNDRED",
        template="(2 * {THIRTY} + 4 * {TEN} = {HUNDRED})",
      )
      
      # solve the puzzle, and output unused digit(s)
      for s in p.solve():
        ds = diff(irange(0, 9), s.values())
        # output solution
        printf("-> unused digits = {ds}", ds=join(ds, sep=", "))
      

      Solution: The missing digit is 7.

      Like

    • GeoffR's avatar

      GeoffR 11:40 am on 10 November 2022 Permalink | Reply

      
      % A Solution in MiniZinc
      include "globals.mzn";
      
      %          T H I R T Y
      %          T H I R T Y
      %                T E N
      %                T E N
      %                T E N
      %                T E N
      %        -------------
      %        H U N D R E D
      %        -------------
      
      set of int: INT = 0..9;
      var INT: T; var INT: H; var INT: I;
      var INT: R; var INT: Y; var INT: E;
      var INT: N; var INT: U; var INT: D;
      
      constraint T > 0 /\ H > 0;
      constraint all_different( [T,H,I,R,Y,E,N,U,D]);
      
      % Carry digits from RH end
      var 0..6:c1; var 0..6:c2; var 0..6:c3;
      var 0..1:c4; var 0..1:c5; var 0..1:c6;
      
      % Adding digits in columns, with carry digits from RH end of sum
      constraint D == (4*N + 2*Y) mod 10 /\ c1 == (4*N + 2*Y) div 10;
      constraint E == (c1 + 4*E + 2*T) mod 10 /\ c2 == (c1 + 4*E + 2*T) div 10;
      constraint R == (c2 + 4*T + 2*R) mod 10 /\ c3 == (c2 + 4*T + 2*R) div 10;
      constraint D == (c3 + 2*I) mod 10 /\ c4 == (c3 + 2*I) div 10;
      constraint N == (c4 + 2*H) mod 10 /\ c5 == (c4 + 2*H) div 10;
      constraint U == (c5 + 2*T) mod 10 /\ c6 == (c5 + 2*T) div 10;
      constraint H == c6;
      
      solve satisfy;
      
      output ["[T,H,I,R,Y,E,N,U,D] = " ++ show([T,H,I,R,Y,E,N,U,D]) ];
      % [T, H, I, R, Y, E, N, U, D] = 
      % [9, 1, 5, 2, 6, 0, 3, 8, 4]
      % ----------
      % ==========
      % By inspection, missing digit = 7.
      % TEN = 903, THIRTY = 915296, HUNDRED = 1834204.
      
      

      Like

    • GeoffR's avatar

      GeoffR 10:25 pm on 10 November 2022 Permalink | Reply

      
      % A Solution in MiniZinc
      include "globals.mzn";
       
      %          T H I R T Y
      %          T H I R T Y
      %                T E N
      %                T E N
      %                T E N
      %                T E N
      %        -------------
      %        H U N D R E D
      %        -------------
       
      set of int: INT = 0..9;
      var INT: T; var INT: H; var INT: I;
      var INT: R; var INT: Y; var INT: E;
      var INT: N; var INT: U; var INT: D;
       
      constraint T > 0 /\ H > 0;
      constraint all_different( [T,H,I,R,Y,E,N,U,D]);
       
      var 100..999:TEN = 100*T + 10*E + N;
      var 100000..999999:THIRTY = 100000*T + 10000*H + 1000*I + 100*R + 10*T + Y;
      var 1000000..9999999:HUNDRED = 1000000*H + 100000*U + 10000*N + 1000*D + 100*R + 10*E + D;
      
      constraint 2 * THIRTY + 4 * TEN == HUNDRED;
      
      solve satisfy;
      
      output [ "T,H,I,R,Y,E,N,U,D] = " ++ show( [T,H,I,R,Y,E,N,U,D] ) ];
      
      % [T, H, I, R, Y, E, N ,U, D] = 
      % [9, 1, 5, 2, 6, 0, 3, 8, 4]
      % time elapsed: 0.17 s
      % ----------
      % ==========
      % By inspection, the missing digit is 7.
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 9:01 am on 8 November 2022 Permalink | Reply
    Tags:   

    Teaser 2695: Powers behind the thrones 

    From The Sunday Times, 18th May 2014 [link] [link]

    Gold sovereigns were minted in London for most years from the great recoinage in 1817 until Britain left the gold standard in 1917. I have a collection of eight sovereigns from different years during that period, the most recent being an Edward VII sovereign (he reigned from 1902 until 1910). I noticed that the year on one of the coins is a perfect square and this set me thinking about other powers. Surprisingly, it turns out that the product of the eight years on my coins is a perfect cube.

    What (in increasing order) are those eight years?

    [teaser2695]

     
    • Jim Randell's avatar

      Jim Randell 9:02 am on 8 November 2022 Permalink | Reply

      The values were are interested in lie in the interval [1817, 1910].

      And the only square in that range is 1849 (= 43²), so that must be one of the 8 values.

      And the largest value is in the interval [1902, 1910].

      This Python program finds the prime factors for numbers in the required range, and then constructs sets of 8 values whose prime factors, when combined, all appear a multiple of 3 times, and so the product of the values is a cube.

      It runs in 164ms.

      Run: [ @replit ]

      from enigma import (irange, prime_factor, multiset, delete, append, printf)
      
      # find values whose product is a cube
      # k = remaining values for find (int)
      # vs = values so far (list)
      # fs = prime factors so far (multiset)
      # d = map of value -> prime factors (multiset)
      # ks = candidate keys in d (list)
      def solve(n, vs, fs, d, ks):
        if n == 0:
          # check all prime exponents are multiples of 3
          if all(x % 3 == 0 for x in fs.values()):
            yield vs
        elif not len(ks) < n:
          # add in a new candidate
          for (i, k) in enumerate(ks):
            # and solve for the remaining candidates
            yield from solve(n - 1, append(vs, k), fs.combine(d[k]), d, ks[i + 1:])
      
      # collect candidate numbers and their prime factors (as a multiset)
      d = dict((n, multiset.from_pairs(prime_factor(n))) for n in irange(1817, 1910))
      
      # find factors that appear fewer than 3 times in total
      while True:
        # count the factors (by combining values from each of the numbers)
        m = multiset.from_dict(*d.values())
        fs = set(k for (k, v) in m.items() if v < 3)
        if not fs: break
        # and remove any numbers which involve any of these factors
        d = delete(d, (k for (k, v) in d.items() if any(p in fs for p in v)))
      
      # 1849 is one of the values in the set
      (vs1, fs1) = ([1849], d[1849])
      
      # and the max value is between 1902 and 1910
      for v in irange(1902, 1910):
        if v not in d: continue
        vs2 = append(vs1, v)
        fs2 = fs1.union(d[v])
      
        # solve for the remaining 6 values
        ks = sorted(k for k in d.keys() if k < v and k not in vs2)
        for vs in solve(6, vs2, fs2, d, ks):
          # output solution
          printf("years = {vs}", vs=sorted(vs))
      

      Solution: The eight years are: 1820, 1836, 1849, 1859, 1870, 1890, 1892, 1904.

      So we have:

      numbers = (1820, 1836, 1849, 1859, 1870, 1890, 1892, 1904)
      factors = (2^12, 3^6, 5^3, 7^3, 11^3, 13^3, 17^3, 43^3)
      factors = (2^4, 3^2, 5, 7, 11, 13, 17, 43)^3

      And the product of the numbers is: (2^4, 3^2, 5, 7, 11, 13, 17, 43)^3 = 526846320^3.

      Like

    • Hugh Casement's avatar

      Hugh Casement 8:31 am on 10 November 2022 Permalink | Reply

      We can get part of the way by analysis.  We need another factor 43, so 1892 must be one of the years.
      The only integer in the range 1902 to 1910 with a small enough largest prime factor to allow us to find two more is 1904 = 2^4 × 7 × 17.
      After that I think trial and error (i.e. by computer) is needed.

      Like

      • Jim Randell's avatar

        Jim Randell 11:03 am on 10 November 2022 Permalink | Reply

        @Hugh: My manual solution proceeded as follows:

        Armed with the prime factorisations of the numbers between 1817 and 1910 (which I did not compute manually), we quickly find 1849, 1892, 1904 are on the list.

        Then we need more factors of 17, and there are only 2 candidates: 1836 and 1870. Both of which must be included. So we now have 5 of the 8 numbers on the list.

        We can eliminate numbers with a factor of 29 (1827, 1856, 1885).

        Considering numbers with factors of 13 (1820, 1859, 1872), if any of these are included it must be 1859 and just one of the others.

        Adding 1859 and 1820 to the list leaves factors of (2, 5, 7) to find, and the only candidate is 1890, and this does indeed give a viable list.

        And I didn’t look for further solutions.

        Like

  • Unknown's avatar

    Jim Randell 8:40 am on 1 November 2022 Permalink | Reply
    Tags:   

    Teaser 2679: Palprimes 

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

    My two pals and I have been considering “palprimes” (i.e. palindromic numbers that are also prime). In particular each of us tried to find a five-figure palprime and I managed to come up with 39293. Then each of my two pals found a five-figure palprime. On comparing them we were surprised to find that overall our three palprimes used all the digits from 1 to 9.

    What were the other two five-figure palprimes?

    [teaser2679]

     
    • Jim Randell's avatar

      Jim Randell 8:41 am on 1 November 2022 Permalink | Reply

      A 5-digit palindrome is of the form XYZYX, so consists of 3 digits.

      In order for 3 of them to use all the digits from 1-9 then each digit can only appear in one prime, and X, Y, Z must be different digits.

      The setter has used 3, 9, 2, so we need to find 2 primes that use the digits 1, 4, 5, 6, 7, 8, between them.

      This Python program runs in 59ms. (Internal runtime is 370µs).

      Run: [ @replit ]

      from enigma import (
        irange, nconcat, diff, is_prime, subsets, partitions, cproduct,
        unpack, printf
      )
      
      # construct a 5-digit palindrome from digits X, Y, Z
      pal5 = unpack(lambda X, Y, Z: nconcat(X, Y, Z, Y, X))
      
      # construct palindromic primes from digits <ds>
      def primes(ds):
        for ss in subsets(ds, size=len, select="P"):
          if is_prime(pal5(ss)):
            yield ss
      
      # digits used in the first prime
      p0 = (3, 9, 2)
      assert is_prime(pal5(p0))
      
      # split the remaining digits for the other 2 primes
      for dss in partitions(diff(irange(1, 9), p0), 3):
        for (p1, p2) in cproduct(primes(ds) for ds in dss):
          printf("{p0} {p1} {p2}", p0=pal5(p0), p1=pal5(p1), p2=pal5(p2))
      

      Solution: The other palprimes are: 16561 and 78487.


      In fact as the palprimes must end (and begin) with one of 1, 3, 7, 9, we can see that the two numbers we have to find must be of the form 1???1 and 7???7. And we just need to work out how to arrange the digits 4, 5, 6, 8 in the middle of them.

      And we can make a slightly shorter program based on this observation:

      Run: [ @replit ]

      from enigma import (nconcat, is_prime, subsets, printf)
      
      # construct a 5-digit palindrome from digits X, Y, Z
      pal5 = lambda X, Y, Z: nconcat(X, Y, Z, Y, X)
      
      # digits used in the first prime
      p0 = pal5(3, 9, 2)
      assert is_prime(p0)
      
      # insert digits 4, 5, 6, 8 in 1???1, 7???7
      for (A, B, C, D) in subsets((4, 5, 6, 8), size=len, select="P"):
        (p1, p2) = (pal5(1, A, B), pal5(7, C, D))
        if is_prime(p1) and is_prime(p2):
          printf("{p0} {p1} {p2}")
      

      Like

    • GeoffR's avatar

      GeoffR 3:59 pm on 1 November 2022 Permalink | Reply

      
      from enigma import is_prime, nsplit
      
      mine = 39293  # given five digit palindromic prime
      mset = {3, 9, 2} # my digit set
      
      #  unused digits are 1, 4, 5, 6, 7, 8 for 2 palprimes
      # range of palindromic primes is from 14841 to 78687
      # find 1st palindromic prime
      for p1 in range(14841, 78687+1):
        if is_prime(p1):
          a, b, c, d, e = nsplit(p1)
          if 0 in (a, b, c, d, e):continue
          if a == e and b == d:
            s2 = set((a, b, c, d, e))
            if len(s2) == 3:  
              if len(mset.union(s2)) == 6:
                  
                # find 2nd palindromic prime 
                for p2 in range(p1+1, 78687+1):
                  if is_prime(p2):
                    f, g, h, i, j = nsplit(p2)
                    if 0 in (f, g, h, i, j):continue
                    if f == j and g == i:
                      s3 = set((f, g, h, i, j))
                      if len(s3) == 3:
                        all_set = mset.union(s2).union(s3)
                        if len(all_set) == 9:
                          print(f"Other two primes are {p1} and {p2}.")
      
      # Other two primes are 16561 and 78487.
      
      

      Like

  • Unknown's avatar

    Jim Randell 9:13 am on 25 October 2022 Permalink | Reply
    Tags:   

    Teaser 2698: Pond plants 

    From The Sunday Times, 8th June 2014 [link] [link]

    John bought some packs of pond plants consisting of oxygenating plants in packs of eight, floating plants in packs of four and lilies in packs of two, with each pack having the same price. He ended up with the same number of plants of each type. Then he sold some of these packs for twenty-five per cent more than they cost him. He was left with just fifty plants (with fewer lilies than any other) and he had recouped his outlay exactly.

    How many of these fifty plants were lilies?

    [teaser2698]

     
    • Jim Randell's avatar

      Jim Randell 9:14 am on 25 October 2022 Permalink | Reply

      If John ends up with L packs of lilies, F packs of floating plants and X packs of oxygenating plants, then we have:

      2L + 4F + 8X = 50

      And if he started out by buying a total of N packs, and selling some (at 25% markup) to cover the cost of the initial purchase, then we have:

      (5/4)(N − (X + F + L)) = N
      N = 5(X + F + L)

      And if he initially purchased n plants of each type we have:

      N = n/8 + n/4 + n/2 = (7/8)n

      This Python program runs in 56ms. (Internal runtime is 210µs).

      Run: [ @replit ]

      from enigma import (express, div, printf)
      
      # consider the make up of the 50 remaining plants
      # L = lily packs, F = floating packs; X = oxygenating packs
      # 2L + 4F + 8X = 50
      for (L, F, X) in express(50, (2, 4, 8)):
        # there are fewer lilies than any other type of plant
        if not (2 * L < min(4 * F, 8 * X)): continue
        # calculate the initial number of packs bought
        N = 5 * (L + F + X)
        # calculate the initial number of plants of each type bought
        n = div(8 * N, 7)
        if n is None: continue
        # output solution (final number of lily plants)
        printf("{x} lily plants [L={L} F={F} X={X} -> N={N} n={n}]", x=2 * L)
      

      Solution: 14 of the remaining 50 plants were lilies.

      Initially John bought 80 of each type of plant (240 plants in total) = 10 packs of oxygenators + 20 packs of floating plants + 40 packs of lilies.

      Of these 70 packs he sold 8 packs of oxygenators + 15 packs of floating plants + 33 packs of lilies. Leaving him with 14 packs.

      The sale of these 56 packs at a 25% markup exactly met the initial cost of the 70 packs.

      Leaving John with 2 packs of oxygenators (= 16 plants) + 5 packs of floating plants (= 20 plants) + 7 packs of lilies (= 14 plants). A total of 50 plants.

      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