This is a intriguing problem, usually stated in terms such as the following:

You are given 12 coins, labeled, but otherwise indistinguishable in appearance, and told that all but one of them (the 'counterfeit', unidentified) are identical in weight.

You are provided with a balance which you may use to compare the weights of equal numbers (up to half the total) of the coins on each side, sufficiently accurate to detect the imbalance which occurs only when the counterfeit participates in a weighing.

Your problem is to identify the counterfeit coin, and also to determine whether it is heavier or lighter than the others, in not more than 3 weighings.

In general, it can be demonstrated that $$n \in \mathbb{N}_0$$ weighings are sufficient to identify the counterfeit among a set of at most $$\frac{3^n - 3}{2}$$ coins.

Assignment

The result of any sequence of $$n$$ weighings can be represented as an $$n$$-digit ternary (base 3) integer (str) that only contains the digits 0, 1 and 2. The consecutive digits (from left to right) correspond to successive weighings, each digit having the following significance:

Such ternary integers are here referred to as weighing patterns, or simply patterns. Since the counterfeit does not necessarily participate in the first weighing, leading zeroes in patterns are significant and must not be suppressed.

A weighing plan gives instructions for $$n$$ weighings that need to be performed to identify the counterfeit among a set of $$m$$ coins (with $$m \leq \frac{3^n - 3}{2}$$). This is done by assigning each coin a unique pattern of $$n$$ weighings (how is not important for this assignment). For example, if each of the 12 coins from the original problem is labeled with a unique letter, this might be the weighing plan for 12 coins:

label pattern
A 112
B 120
C 121
D 122
E 220
F 201
G 202
H 200
I 001
J 012
K 010
L 011

For the $$i$$-th weighing ($$i = 0, 1, \ldots, n - 1$$), the $$i$$-th digit (from the left) of each pattern indicates how the corresponding coin participates in the weighing:

Both sides of the balance always have the same number of coins, and each coin is weighed at least once (in other words, the pattern 00…0 does not appear in the weighing plan). For example, the weighing plan for 12 coins indicates that the following weighings must be performed:

weighing left side (1) right side (2)
0 A, B, C, D E, F, G, H
1 A, J, K, L B, C, D, E
2 C, F, I, L A, D, G, J

To identify the counterfeit, the results of the successive weighings must be listed in the form of a "pattern": the first digit indicates the result of first weighing, the second digit indicates the result of the second weighing, and so on. The digits have the following significance:

Now there are two possibilities:

The converse of a pattern $$p$$ is defined as the pattern obtained by replacing each occurrence of the digit 2 by the digit 1 in pattern $$p$$, and replacing each occurrence of the digit 1 by the digit 2.

Your task:

Example

In the following interactive session, we assume the text file plan.txt1 to be located in the current directory.

>>> converse('102')
'201'
>>> converse('200')
'100'

>>> balance({'A', 'B', 'C', 'D'}, {'E', 'F', 'G', 'H'}, 'F')
1
>>> balance({'A', 'B', 'C', 'D'}, {'E', 'F', 'G', 'H'}, 'F', True)
2
>>> balance({'A', 'J', 'K', 'L'}, {'B', 'C', 'D', 'E'}, 'F')
0
>>> balance({'A', 'J', 'K', 'L'}, {'B', 'C', 'D', 'E'}, 'F', True)
0
>>> balance({'C', 'F', 'I', 'L'}, {'A', 'D', 'G', 'J'}, 'F')
2
>>> balance({'C', 'F', 'I', 'L'}, {'A', 'D', 'G', 'J'}, 'F', heavier=True)
1

>>> plan = labels('plan.txt2')
>>> plan['121']
'C'
>>> plan['202']
'G'
>>> plan['011']
'L'

>>> weighing = weighing_plan(plan)
>>> weighing[0]
({'A', 'B', 'C', 'D'}, {'E', 'F', 'G', 'H'})
>>> weighing[1]
({'A', 'J', 'K', 'L'}, {'B', 'C', 'D', 'E'})
>>> weighing[2]
({'C', 'F', 'I', 'L'}, {'A', 'D', 'G', 'J'})

>>> weighing_pattern(plan, 'F')
'102'
>>> weighing_pattern(plan, 'F', True)
'201'
>>> weighing_pattern(plan, 'H', heavier=False)
'100'
>>> weighing_pattern(plan, 'H', heavier=True)
'200'

>>> counterfeit(plan, '102')
('F', False)
>>> counterfeit(plan, '200')
('H', True)

Resources