Dit is een bekend raadsel dat doorgaans op de volgende manier wordt omschreven:

We hebben 12 muntstukken een uniek label gegeven, maar voor rest zien ze er exact hetzelfde uit. Alle muntstukken hebben hetzelfde gewicht, behalve één dat lichter of zwaarder is dan de rest. Dat noemen we het vervalste muntstuk, maar uiteraard zeggen we niet over welk muntstuk het gaat.

Je krijgt een weegschaal die je mag gebruiken om het gewicht te vergelijken van een gelijk aantal muntstukken (tot maximaal de helft van het totaal aantal muntstukken) die aan de linker- en rechterkant van de weegschaal gelegd worden. De weegschaal is voldoende nauwkeurig om het onevenwicht te bepalen dat optreedt als het vervalste muntstuk bij de gewogen muntstukken zit.

Je opdracht bestaat erin om het vervalste muntstuk te vinden, en ook om te bepalen of het lichter of zwaarder is dan de rest van de muntstukken, door maximaal drie wegingen uit te voeren.

Er kan echter algemeen aangetoond worden dat $$n \in \mathbb{N}_0$$ wegingen volstaan om een vervalst muntstuk te identificeren uit een reeks van maximaal $$\frac{3^n - 3}{2}$$ muntstukken.

Opgave

De uitkomsten van een reeks van $$n$$ wegingen kunnen voorgesteld worden als een string (str) van $$n$$ cijfers: 0, 1 of 2. Daarbij stellen de opeenvolgende cijfers (van links naar rechts) de uitkomsten van de opeenvolgende wegingen voor, waarbij de cijfers de volgende betekenis hebben:

We noemen zo'n string een weegpatroon, of kortweg een patroon. Omdat het vervalste muntstuk niet noodzakelijk bij de gewogen muntstukken van de eerste weging zit, hebben voorloopnullen wel degelijk betekenis en mogen dus niet weggelaten worden.

Een weegplan geeft aan welke $$n$$ wegingen we moeten uitvoeren om het vervalste muntstuk te vinden uit een reeks van $$m$$ muntstukken (met $$m \leq \frac{3^n - 3}{2}$$). Dit gebeurt door aan elk muntstuk een uniek patroon van $$n$$ wegingen toe te kennen (hoe is voor deze opgave niet belangrijk). Als we elk van de 12 muntstukken uit het originele raadsel labelen met een unieke letter, dan ziet een weegplan voor 12 muntstukken er bijvoorbeeld als volgt uit:

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

Voor de $$i$$-de weging ($$i = 0, 1, \ldots, n - 1$$) geeft het $$i$$-de cijfer van elk patroon (geteld vanaf links) als volgt aan hoe het muntstuk deelneemt in de weging:

Hierbij geldt dat er altijd evenveel muntstukken aan beide kanten van de weegschaal liggen, en dat elk muntstuk minstens één keer gewogen wordt (met andere woorden, het patroon 00…0 komt niet in het weegplan voor). Het weegplan voor 12 muntstukken geeft bijvoorbeeld aan dat de volgende wegingen moeten uitgevoerd worden:

weging linkerkant (1) rechterkant (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

Om het vervalste muntstuk te vinden, moet je de uitkomsten van de opeenvolgende wegingen oplijsten in de vorm van een "patroon": het eerste cijfer correspondeert met de uitkomst van de eerste weging, het tweede cijfer met de uitkomst van de tweede weging, enzoverder. Daarbij hebben de cijfers de volgende betekenis:

Nu zijn er twee mogelijkheden:

Hierbij is het omgekeerde van een patroon $$p$$ gedefinieerd als het patroon dat men bekomt door in $$p$$ elk voorkomen van het cijfer 2 te vervangen door het cijfer 1, en elk voorkomen van het cijfer 1 te vervangen door het cijfer 2.

Gevraagd wordt:

Voorbeeld

In onderstaande voorbeeldsessie gaan we ervan uit dat het tekstbestand plan.txt1 zich in de huidige directory bevindt.

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

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

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

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

>>> weegpatroon(plan, 'F')
'102'
>>> weegpatroon(plan, 'F', True)
'201'
>>> weegpatroon(plan, 'H', zwaarder=False)
'100'
>>> weegpatroon(plan, 'H', zwaarder=True)
'200'

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

Bronnen