Enigmatic Code

Programming Enigma Puzzles

Enigma 1597: Next door

From New Scientist #2762, 29th May 2010 [link]

An encyclopaedia salesman was working his way along a row of terraced houses. His standard patter was to ask about the children in the household. At one house the lady who answered the door told him: “I have three children. The product of their ages is 72. The sum of their ages equals the number of an adjoining house next door.” It was impossible for the salesman to work out the ages from this.

At the next house the lady who answered the door told him “I have three children. The product of their ages is 72. The sum of their ages equals the number of an adjoining house next door.” It was impossible for the salesman to work out the ages from this either. At the next house exactly the same thing happened again, and it was impossible for the salesman to work out the ages.

At a house a little further along the terrace exactly the same thing happened again and it was impossible for the salesman to work out the ages. At the next house exactly the same thing happened again, but this time the salesman was able to work out their ages.

What were they?

[enigma1597]

Advertisements

2 responses to “Enigma 1597: Next door

  1. jimrandell 11 January 2012 at 6:29 pm

    It’s a bit tricky to work out what is required here. Does the salesmen go along the street by increasing number, or decreasing number? Are the houses numbered consecutively, or does each differ from its neighbours by 2? Can “a little further along the terrace” mean next door, or not?

    You can make a more complicated version of the program below and discover that the houses need to be numbered consecutively, and the salesman must visit them in increasing order. If you interpret “a little further along the terrace” to include next door, then you get an additional way of solving the puzzle, but it doesn’t affect the answer.

    Given those constraints this Python program runs in 33ms.

    from itertools import count
    from collections import defaultdict
    
    # factor n into i numbers
    def factor(n, i):
      if i == 1: return [[n]]
      l = []
      for a in count(1):
        if a * a > n: break
        (b, r) = divmod(n, a)
        if r > 0: continue
        l.extend([a] + f for f in factor(b, i - 1) if not(f[0] < a))
      return l
    
    # index the factors by sum neighbours
    n = defaultdict(list)
    for f in factor(72, 3):
      s = sum(f)
      n[s-1].append(f)
      n[s+1].append(f)
    
    # we need to find three neighbouring houses with multiple possibilities
    k = sorted(n.keys())
    for i in range(k[0], k[-1] + 1):
      if not(len(n[i]) > 1 and len(n[i + 1]) > 1 and len(n[i + 2]) > 1): continue
      # and find a further set of two neighbouring houses where the first has
      # multiple possibilities, and the second has only a single possibility
      # (use i+4 below if you insist "a little further along" can't mean "next door")
      for j in range(i + 3, k[-1] + 1):
        if not(len(n[j]) > 1 and len(n[j + 1]) == 1): continue
        print(n[j + 1][0], (i, i + 1, i + 2), (j, j + 1))
    

    Solution: The children’s ages are 1, 8 and 9.

    • jimrandell 11 January 2012 at 6:38 pm

      And here’s the modified version which checks for the houses going in increments of 1 or 2 and also for the salesmen visiting the houses in increasing or decreasing order.

      The runtime is also 33s.

      from itertools import count
      from collections import defaultdict
      
      # factor n into i numbers
      def factor(n, i):
        if i == 1: return [[n]]
        l = []
        for a in count(1):
          if a * a > n: break
          b, r = divmod(n, a)
          if r > 0: continue
          l.extend([a] + f for f in factor(b, i-1) if not(f[0] < a))
        return l
      
      # index the factors by sum
      d = defaultdict(list)
      for f in factor(72, 3):
        d[sum(f)].append(f)
      
      def check(s=1):
        # are we going up or down the street
        start, finish = (min, max) if s > 0 else (max, min)
      
        # index factors by neighbours
        n = defaultdict(list)
        for k, v in d.items():
          n[k-s].extend(v)
          n[k+s].extend(v)
      
        # we need to find three neighbouring houses with multiple possibilities
        k = sorted(n.keys())
        ks = (k[0], k[-1])
        for i in range(start(ks), finish(ks)+s):
          if not(len(n[i]) > 1 and len(n[i+s]) > 1 and len(n[i+2*s]) > 1): continue
          # and find a further set of two neighbouring houses where the first has
          # multiple possibilities, and the second has only a single possibility
          # (or i+4*s if you insist "a little further along" can't mean "next door")
          for j in range(i+3*s, finish(ks)+s, s):
            if not(len(n[j]) > 1 and len(n[j+s]) == 1): continue
            print(s, n[j+s][0], (i, i+s, i+s+s), (j, j+s))
      
      
      for s in (-2, -1, 1, 2):
        check(s)
      

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: