Enigmatic Code

Programming Enigma Puzzles

Enigma 403: Taking stock

From New Scientist #1553, 26th March 1987 [link]

“What animals have you in that barn there?” said the man from the ministry.

The farmer beamed. “Pigs, cows and ducks, sir.”

“How many are there, though?”

“Oh, quite a few, really, sir.”

“I need figures, man!” persevered the would-be census taker.

“If it’s figures you’ll be wanting, sir,” replied the farmer, “I can tell you that multiplying the number of horns by the number of legs by the number of wings gives 720.”

“Yes, but how many of each animal are there?” snapped the other exasperatedly.

“Telling you the number of cows alone wouldn’t enable you to deduce the number of ducks and pigs. Telling you the number of ducks alone wouldn’t enable you to deduce the number of pigs and cows. But telling you the number of pigs would enable you to deduce the number of cows and ducks right enough. So I reckon you can work out how many cows and ducks there be in yonder barn even if I don’t tell you the number of pigs in it.”

With that he ducked into a hen-house.

How many cows, ducks and pigs were there in the barn?

[enigma403]

Advertisements

3 responses to “Enigma 403: Taking stock

  1. Jim Randell 29 June 2017 at 10:27 pm

    I assumed that each cow has 4 legs, 2 horns and no wings, each duck has 2 legs, no horns and 2 wings, each pig has 4 legs, no horns and no wings.

    This Python program runs in 39ms.

    # if we have C cows, D ducks and P pigs, then the measure M is the
    # product of the number of horns (2 per cow), the number of legs (4
    # per cow, 2 per duck, 4 per pig) and the number of wings (2 per
    # duck):
    #
    #   M = 2C (4C + 2D + 4P) 2D
    #     = 4CD(4C + 2D + 4P)
    #     = 16(C^2)D + 8C(D^2) + 16CDP
    #     = 8(2(C^2)D + C(D^2) + 2CDP)
    #
    # and in this case it is 720, so we are interested in:
    #
    #   2(C^2)D + C(D^2) + 2CDP = 90
    #
    #   P = (90 - 2(C^2)D - C(D^2)) / 2CD
    
    from collections import namedtuple
    from itertools import count
    from enigma import filter_unique, printf
    
    Result = namedtuple('Result', 'C D P')
    
    ss = list()
    for C in count(1):
      for D in count(1):
        x = 90 - 2 * C * C * D - C * D * D
        if x < 1: break
        (P, r) = divmod(x, 2 * C * D)
        if r != 0: continue
        printf("[C={C} D={D} P={P}]")
        ss.append(Result(C, D, P))
      if D == 1: break
    
    # the number of cows give multiple solutions
    (_, s1) = filter_unique(ss, (lambda r: r.C))
    
    # the number of ducks gives multiple solutions
    (_, s2) = filter_unique(ss, (lambda r: r.D))
    
    # the number of pigs gives a unique solution
    (s3, _) = filter_unique(ss, (lambda r: r.P))
    
    # the solution is in all three sets
    for (C, D, P) in set(s1).intersection(s2, s3):
      printf("C={C} D={D} P={P}")
    

    Solution: There are 2 cows, 1 duck, and 20 pigs.

    Altogether there are 4 horns (on the cows), 90 legs (8 on the cows, 2 on the duck, 80 on the pigs) and 2 wings (on the duck), giving a product of 720.

  2. geoffrounce 29 June 2017 at 11:08 pm
    for p in range(1,150):
      for c in range(1,150):
        for d in range(1,150):
          legs = p*4 + c*4 + d*2
          horns = c*2
          wings = d*2
          if horns * legs * wings == 720:
            print('pigs = {}, cows = {}, ducks = {}'. format(p,c,d ))
            print('legs = {}, horns = {}, wings = {}'.format(legs,horns,wings))
            print()
    
    '''
    Outputs and Solution
    --------------------
    1) pigs = 1, cows = 6, ducks = 1
    legs = 30, horns = 12, wings = 2
    
    2) pigs = 4, cows = 2, ducks = 3
    legs = 30, horns = 4, wings = 6
    
    3) pigs = 20, cows = 2, ducks = 1
    legs = 90, horns = 4, wings = 2
    '''
    
    # The number of ducks (solutions 1 and 3) gives multiple solutions
    # The number of cows  (solutions 2 and 3) gives multiple solutions
    # Only solution 3, based on the number of pigs, gives a unique solution
    # ie 20 pigs, 2 cows and 1 duck
    
  3. Brian Gladman 1 July 2017 at 12:20 am
    from collections import defaultdict
    from number_theory import divisor_pairs
    
    # split a set of tuples (t) into two sets that are
    # respectively unique and non-unique  with respect
    # to the value at position (i) in the tuples 
    def split(t, i):
      d = defaultdict(list)
      for x in t:
        d[x[i]].append(x)
      u, v = set(), set()
      for k in d:
        (u if len(d[k]) == 1 else v).update(d[k])
      return u, v
    
    # find all triples (c, d, p) for the numbers of cows,
    # ducks and pigs for which c.d.(2.c + d + 2.p) = 90
    sols = set()
    for c, x in divisor_pairs(90):
      for d, y in divisor_pairs(x):
        p, r = divmod(y - 2 * c - d, 2)
        if not r and p > 0:
          sols.add((c, d, p))
          
    # add an 's' for plural numbers (n) of type (t) 
    pl = lambda n, ty: '{} {}{}'.format(n, ty, 's' if n > 1 else '')
    
    # 0. knowing the number of cows does not reveal the number of ducks and pigs 
    # 1. knowing the number of ducks does not reveal the number of cows and pigs 
    # 2. knowing the number of pigs reveals the number of cows and ducks 
    for c, d, p in split(sols, 0)[1] & split(sols, 1)[1] & split(sols, 2)[0]:
      print('{}, {} and {}'.format(pl(c, 'cow'), pl(d, 'duck'), pl(p, 'pig')))
    

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: