Tagged: by: F. Moore Toggle Comment Threads | Keyboard Shortcuts

  • Unknown's avatar

    Jim Randell 9:21 am on 9 May 2021 Permalink | Reply
    Tags: by: F. Moore   

    Brain-Teaser 33: Postal purchases 

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

    A rectangular sheet of postage stamps (i.e., one with each row containing the same number of stamps) was sold in such a way that each successive customer bought either a complete row or a complete column, thereby leaving the sheet rectangular after each purchase.

    The 2nd customer bought 6 stamps more than the 4th and half as many again as the 6th customer. The 5th customer bought twice as many stamps as the 12th. After the 7th customer had made his purchase exactly one-third of the original sheet had been sold.

    What was the size of the original sheet of stamps? And what was the total number of stamps bought by the first 12 customers?

    [teaser33]

     
    • Jim Randell's avatar

      Jim Randell 9:21 am on 9 May 2021 Permalink | Reply

      (See also: Enigma 460).

      This Python program runs in 51ms.

      Run: [ @replit ]

      from enigma import (irange, inf, printf)
      
      # make k purchases from an (x, y) rectangle
      def solve(k, x, y, t, ss=[]):
        # perform checks:
        n = len(ss)
        # the 2nd purchase is divisible by 3 and is greater than 6
        if n == 2 and not (ss[1] > 6 and ss[1] % 3 == 0): return
        # the 4th purchase is the 2nd less 6
        if n == 4 and not (ss[3] == ss[1] - 6): return
        # the 5th purchase is divisible by 2
        if n == 5 and not (ss[4] % 2 == 0): return
        # the 6th purchase is (2/3) the 2nd
        if n == 6 and not (ss[5] * 3 == ss[1] * 2): return
        # after the 7th purchase 1/3 of the original sheet is sold
        if n == 7 and not (sum(ss) * 3 == t): return
        # the 12th purchase is half the 5th
        if n == 12 and not (ss[11] * 2 == ss[4]): return
      
        # are we done?
        if k == 0:
          yield ss
        else:
          if y > 1:
            # buy a row of x stamps
            yield from solve(k - 1, x, y - 1, t, ss + [x])
          if x > 1:
            # buy a column of y stamps
            yield from solve(k - 1, x - 1, y, t, ss + [y])
      
      # diagonal enumeration of (x, y) pairs, x > y
      def pairs(a, b):
        # consider the sum of the dimensions
        for t in irange(a, b):
          # values for y
          for y in irange(1, t // 2):
            yield (t - y, y)
      
      def run():
        # consider (x, y) rectangles
        for (x, y) in pairs(12, inf):
          # attempt 12 purchases
          for ss in solve(12, x, y, x * y):
            yield (x, y, ss)
      
      for (x, y, ss) in run():
        printf("x={x} y={y}: {ss} -> {t}", t=sum(ss))
        break
      

      Solution: The original sheet consisted of 21 × 18 stamps (= 378 stamps in total). Between them, the 12 customers purchased 208 stamps.

      The individual purchases were (1st – 12th): 21, 21, 21, 15, 20, 14, 14, 18, 18, 18, 18, 10.

      The following diagram shows one way the original sheet could have been sold. Each purchase is numbered, and the number of stamps bought is given in brackets.

      Initially there are 378 stamps in the sheet.

      After the first 7 purchases (shown in red) the yellow and green squares remain. A total of 252 stamps, which is 2/3 of the original 378 stamps, so 1/3 have been sold.

      After all 12 purchases (red and yellow) only the green squares remain. A total of 170 stamps, so 208 stamps have been sold in all.

      Like

      • Frits's avatar

        Frits 10:41 am on 1 June 2021 Permalink | Reply

        You can already skip (x, y) combinations in run() if x * y is not a multiple of 3.

        Like

    • Frits's avatar

      Frits 11:20 am on 2 June 2021 Permalink | Reply

      Only one (x, y) rectangle is possible (without even considering purchases as the 6th).
      Second question is not dealt with.

      from enigma import irange
        
      # the 2nd purchase is divisible by 3 and is greater than 6
      # the 4th purchase is the 2nd less 6
      # the 5th purchase is divisible by 2
      # the 6th purchase is (2/3) the 2nd
      # after the 7th purchase 1/3 of the original sheet is sold
      # the 12th purchase is half the 5th
       
      # diagonal enumeration of (x, y) pairs, x > y
      def pairs(a, b):
        # consider the sum of the dimensions
        for t in irange(a, b):
          # values for y
          for y in irange(1, t // 2):
            yield (t - y, y)
            
      for (x, y) in pairs(12, 196):              # assume x < 100
        # consider x, y with y + 3 <= x <= y + 7 (purchase 2 and 4 rules)
        # and                x % 3 != 2          (purchase 2 rule)
        # purchase 7 rule makes x * y a multiple of 3
        if (x * y) % 3 or x < y + 3 or x > y + 7 or x % 3 == 2: continue
        
        # 2nd purchase comes from initial long side
        # 4th purchase comes from initial short side 
        for a in range(1, 7): 
          b = 7 - a
          # after the 7th purchase 1/3 of the original sheet is sold
          if (x - a) * (y - b) * 3 != 2 * (x * y): continue
             
          # if only 2nd purchase made from initial long side (b = 1)
          if b == 1:
            # 1st purchase is made from the initial short side 
            if (x - 1) % 3: continue
            
            # if y is odd then the 5th purchase is odd, impossible
            if y % 2: continue
            
            # purchases 3 - 7 must be equal to 2nd purchase - 6 (and even)
            # so 2nd purchase must be even as well
            if x % 2: continue
            
          
          # if only 4th purchase made from initial short side (a = 1)
          if a == 1:
            # x must be three higher than y (the 4th purchase is the 2nd less 6)
            if x != y + 3: continue
          
          # if initial long side is a multiple of 3 
          if x % 3 == 0: 
            # the 1st purchase must be made from the long side 
            # after the first 2 purchases the short side has decremented with 2
            if x > y + 4: continue    # 4th purchase rule
            
            if x == y + 4:
              # the 3rd purchase must be made from the initial short side 
              # (difference between sides may not become higher than 6)
              # so both sides after 4 purchases have decremented with 2
              if x % 2 and y % 2: continue    # 5th purchase must be even
         
          print(f"{(x, y) = } {(a, b) = } remaining {(x - a), (y - b) = }")
      
      # (x, y) = (21, 18) (a, b) = (3, 4) remaining (x - a), (y - b) = (18, 14)
      

      Like

  • Unknown's avatar

    Jim Randell 8:53 am on 21 February 2021 Permalink | Reply
    Tags: by: F. Moore   

    Brain-Teaser 23: [Money sharing] 

    From The Sunday Times, 27th August 1961 [link]

    A man divided 8s. 4d. among his three sons so that the difference between the shares of the eldest and youngest, expressed in halfpence, was a perfect square. The total of Alan’s and Bob’s shared was an exact multiple of 5½d.; the total of Bob’s and Clive’s shares an exact multiple of 6½d.; and the total of Alan’s and Clive’s shares an exact multiple of 9½d.

    What was the name of the second son, and what was his share?

    This puzzle was originally published with no title.

    [teaser23]

     
    • Jim Randell's avatar

      Jim Randell 8:55 am on 21 February 2021 Permalink | Reply

      1s = 12d.

      Working in half-pennies (hp) the total amount to distribute is 100 d = 200 hp.

      And we are told:

      11 | (A + B)
      13 | (B + C)
      19 | (A + C)

      And the difference between two of the numbers is a square number of half pennies.

      The following Python program runs in 53ms.

      Run: [ @repl.it ]

      from enigma import irange, is_square, div, printf
      
      # solve the equations
      def solution(middle, AB, AC, BC):
        A = div(AB + AC - BC, 2)
        B = div(AB + BC - AC, 2)
        C = div(AC + BC - AB, 2)
        if not any(x is None or x < 0 for x in (A, B, C)):
          # output solution
          printf("A={A} hp, B={B} hp, C={C} hp; middle = {middle}")
      
      # A + C is some multiple of 19
      for AC in irange(19, 200, step=19):
      
        # B + C is some multiple of 13
        for BC in irange(13, 200, step=13):
      
          # A + B is some multiple of 11
          # and (A + B) + (B + C) + (A + C) = 2(A + B + C) = 400
          AB = 400 - (AC + BC)
          if AB % 11 > 0: continue
      
          # one of the differences is a square
          # B - C = (A + B) - (A + C)
          if is_square(abs(AB - AC)): solution('A', AB, AC, BC)
          # A - C = (A + B) - (B + C)
          if is_square(abs(AB - BC)): solution('B', AB, AC, BC)
          # A - B = (A + C) - (B + C)
          if is_square(abs(AC - BC)): solution('C', AB, AC, BC)
      

      Solution: The middle son was Clive. His share was 45d = (3s 9d).

      The shares are:

      A: 5 hp = 2.5 d
      B: 105 hp = 52.5 d (= 4s 4.5d)
      C: 90 hp = 45 d (= 3s 9d)

      And we see:

      A + B = 110 hp = 10× 11 hp
      B + C = 195 hp = 15× 13 hp
      A + C = 95 hp = 5× 19 hp

      And the difference between the eldest and the youngest is: BA = 10² hp.

      Like

    • Frits's avatar

      Frits 11:53 am on 21 February 2021 Permalink | Reply

      from enigma import SubstitutedExpression, is_square, peek
      
      # the alphametic puzzle
      p = SubstitutedExpression(
        [# A = AST, B = BVW, C = CYZ
        
        # start with the most restrictive constraint
        
        # A + C is some multiple of 19
        "(AST + CYZ) % 19 == 0",
        
        # divide 200 half-pennies over 3 sons
        "200 - AST - CYZ = BVW", 
        
        # B + C is some multiple of 13
        "(BVW + CYZ) % 13 == 0",
        
        # A + B is some multiple of 11
        "(AST + BVW) % 11 == 0",
        
        # difference between the eldest and youngest was a perfect square
        "peek(2 - i for (i, (x, y)) in \
         enumerate(zip([AST, CYZ, BVW], [BVW, AST, CYZ])) \
         if is_square(abs(x - y))) = I",
        ],
        answer="I, [AST, BVW, CYZ][I]",
        d2i=dict([(2, "ABC")] + [(k, "ABCI") for k in range(3, 10)]),
        distinct="",
        reorder=0,
        verbose=0)   
      
      for (_, ans) in p.solve():
        print(f"{['Alan', 'Bob', 'Clive'][ans[0]]} with share {ans[1]} half-pennies")
      

      Like

      • Jim Randell's avatar

        Jim Randell 12:49 pm on 21 February 2021 Permalink | Reply

        Here’s an alternative solution using the [[ SubstitutedExpression() ]] solver:

        from enigma import (SubstitutedExpression, subsets, is_square, printf)
        
        # find candidate (A, B, C) values
        p = SubstitutedExpression(
          [ "A + B + C == 200", "(A + B) % 11 = 0", "(B + C) % 13 = 0", "(A + C) % 19 = 0" ],
          base=201,
          distinct=(),
          answer="(A, B, C)",
          template="",
        )
        
        # look at possible (A, B, C) values
        for (_, vs) in p.solve(verbose=0):
          # the values for the eldest and youngest differ by a square number
          for ((i, x), (j, y)) in subsets(enumerate(vs), size=2):
            if is_square(abs(x - y)):
              # identify the middle son
              m = "ABC"[3 - i - j]
              printf("A={vs[0]} hp, B={vs[1]} hp, C={vs[2]} hp; middle={m}")
        

        Like

    • Hugh Casement's avatar

      Hugh Casement 1:51 pm on 21 February 2021 Permalink | Reply

      Theoretically Alan and Clive could each have received 57 ha’pence and Bob 86.
      Zero is also a square number! However, I doubt that is the intended solution.

      Like

      • Jim Randell's avatar

        Jim Randell 2:02 pm on 21 February 2021 Permalink | Reply

        @Hugh: Well spotted!

        In my programs, both 0 and None evaluate to false, so using the return value from [[ is_square() ]] as a boolean value will reject 0. (It also doesn’t consider 0 to be allowed as a multiple of 11, 13, 19).

        You can explicitly check [[ is_square(...) is not None ]], or just import [[ is_square_p() ]] instead which returns a boolean.

        And if you do that you do indeed get two solutions:

        % python teaser23b.py
        A=5 hp, B=105 hp, C=90 hp; middle = C
        A=57 hp, B=86 hp, C=57 hp; middle = B
        

        The published solution is: “Clive, 3s 9d”.

        Perhaps the setter intended the shares to be three different values.

        Like

    • John Crabtree's avatar

      John Crabtree 6:58 pm on 22 February 2021 Permalink | Reply

      Working in 1/2d, then A + B + C = 200
      A + B = 11p, p ≤ 18
      B + C = 13q, q ≤ 15
      A + C = 19r, r ≤ 10
      Summing the three gives 400 = 11p + 13q + 19r
      Using r as a variable as it has the fewest possible values:
      B = 200 – 19r, p = 8 + 3r mod 13, q = 3 + 7r mod 11 which leads to
      A = 31 + 52r mod 143
      C = 112 + 110r mod 143
      It is then straightforward to manually generate a table of values for A, B and C for each r. r = 1, 2 and 4 give A+B+C = 343. r = 3 and r = 5 to 10 give A+B+C = 200 and include the two solutions noted by Jim.

      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