Zwölf-Münzen-Problem

14

Hintergrund

Das Zwölf-Münzen-Problem ist ein klassisches Balance-Puzzle, das häufig in Vorstellungsgesprächen verwendet wird. Das Rätsel erschien zum ersten Mal im Jahr 1945 und wurde meinem Vater von meinem Großvater gestellt, als er darum bat, meine Mutter zu heiraten! In dem Puzzle gibt es zwölf Münzen, von denen eine entweder schwerer oder leichter als die anderen ist (Sie wissen nicht, welche). Das Problem besteht darin, eine Waage dreimal zu verwenden, um die eindeutige Münze zu bestimmen. In einigen Varianten muss auch festgestellt werden, ob die Münze schwerer oder leichter ist.

Hier geht es darum, das allgemeine Problem mit n Münzen zu lösen und im ungünstigsten Fall möglichst wenig zu wiegen. Es muss nicht festgestellt werden, ob die Münze schwerer oder leichter ist, sondern nur, um welche es sich handelt. Darüber hinaus haben Sie keinen Zugriff auf zusätzliche Münzen außerhalb des angegebenen Satzes (was merkwürdigerweise einen Unterschied macht).

Es zeigt sich, dass k-Wägungen für bis zu (3 ^ k-1) / 2 Münzen ausreichen (4 Wägungen in dieser Variante können also tatsächlich 13 Münzen verarbeiten). Darüber hinaus ist es (und überraschenderweise) möglich (hier jedoch nicht erforderlich), den vollständigen Satz von Wägungen im Voraus auszuwählen, anstatt dass zukünftige Wägungen von früheren Ergebnissen abhängen. Beschreibungen von zwei möglichen Lösungen finden Sie in diesem Dokument und in dieser Quora-Antwort .

Aufgabe

Schreiben Sie eine Funktion oder ein Programm, indem Sie eine Ganzzahl n über STDIN, ein Befehlszeilenargument oder ein Funktionsargument als Eingabe verwenden. Dadurch wird das Problem für n Münzen mit den geringstmöglichen Gewichten im ungünstigsten Fall gelöst . Das Programm sollte:

  • Drucken Sie die Wägungen im Format auf STDOUT 1,2,3-4,5,6, um die Münzlisten auf jeder Seite der Waage anzuzeigen. Nicht gewogene Münzen sollten nicht erwähnt werden. Die Münzen implizit aus 1 nummeriert sind n und nicht in numerischer Reihenfolge gedruckt werden müssen (so 2,1-3,4ist die gleiche wie zu 1,2-3,4).
  • Nachdem jeder das Programm mit einem Gewicht an einem Eingang über STDIN warten sollte, was sein sollte <, =oder >, das anzeigt , ob die linke Seite der Skala ist leichter, gleich, oder schwerer als die rechte Seite.
  • Nach dem letzten Wägeresultat sollte das Programm die Nummer der einzelnen Münze drucken oder zurückgeben.
  • Das Programm muss keine inkonsistenten Ergebnisseingaben des Benutzers verarbeiten.
  • Das Programm muss nicht handhaben n weniger als 3.

Beispielausgaben

>> 3
1-2
>> =
1-3
>> <
3

# using Quora algorithm
>> 13
1,2,3,4-5,6,7,8
>> <
1,2,5-3,4,6
>> >
3-4
>> <
3

# using paper algorithm
>> 13
1,2,3,4-5,6,7,8
>> <
2,6,7,9-3,8,10,11
>> >
6,8,10,12-4,5,7,11
>> =
3

Wertung

Kürzester Code gewinnt. Es gelten Standardregeln.

Uri Granta
quelle

Antworten:

2

Python 3: 497 Bytes

I=lambda a,b:input(",".join(a)+"-"+",".join(b)+"\n>> ")
def A(a,b):
 l,L=len(a),len(b)
 if l+L==1:return(a or b)[0]
 m=(2*l+1-L)//3;M=m+L-l;x,y,X,Y=a[:m],a[m:2*m],b[:M],b[M:2*M];r=I(x+X,y+Y);return A(a[2*m:],b[2*M:])if r=="="else A(x,Y)if r=="<"else A(y,X)
def B(a,n=[]):
 if len(a)==1:return a[0]
 m=len(n);l=(len(a)+1+m)//3;x,y,z=a[:l],a[l:2*l-m],a[2*l-m:];r=I(x,y+n);return B(z,a[:1])if r=="="else A(x+z[:1-m],y)if r=="<"else A(y+z[:1-m],x)
print(B(list(map(str,range(1,int(input("N= "))+1)))))

Ich vermute, dass dies ein bisschen mehr geschrumpft werden könnte, aber ich sehe keine offensichtlichen Stellen mehr (nach ungefähr 5 verschiedenen Versionen jeder Funktion).

Der Code implementiert eine leicht modifizierte Version des Algorithmus von dieser Seite mit drei Funktionen. Die IFunktion übernimmt die E / A (Drucken der Optionen und Zurücksenden der Benutzerantwort). Die Aund BFunktionen implementieren den Hauptteil des Algorithmus. AEs werden zwei Listen verwendet, die sich in der Größe um genau ein Element unterscheiden (obwohl jede Liste die größere sein kann): Eine Münze ist amöglicherweise leichter als normal, oder eine Münze ist bmöglicherweise schwerer. Btut doppelte Pflicht. Es wird eine Liste mit Münzen aund optional eine zweite Liste mit einer einzelnen Münze benötigt, von der bekannt ist, dass sie das richtige Gewicht hat. Das Längenrundungsverhalten muss zwischen den beiden Fällen unterschiedlich sein, was zu keinem Ende der Kopfschmerzen geführt hat.

Die beiden Algorithmusfunktionen können die ungewöhnlich gewichtete Münze in kWägungen mit Eingaben von bis zu folgenden Größen finden:

  • A: 3^kGesamtmünzen, aufgeteilt in zwei Listen von (3^k-1)/2und (3^k+1)/2.
  • B: (3^k + 1)/2Münzen, wenn eine bekanntermaßen gute Münze geliefert wird, (3^k - 1)/2 ansonsten.

Die gestellten Frage hier gibt an, dass wir haben noch keine bekannt-gute Münzen am Anfang, so dass wir die schlechte Münze in einem Satz finden lösen können (3^k - 1)/2in kWägungen.

Hier ist eine Testfunktion, die ich geschrieben habe, um sicherzustellen, dass mein Code keine falschen Wägungen anfordert oder mehr als die vorgesehene Anzahl von Wägungen verwendet:

def test(n):
    global I
    orig_I = I
    try:
        for x in range(3,n+1):
            max_count = 0
            for y in range(x*2):
                count = 0
                def I(a, b):
                    assert len(a) == len(b), "{} not the same length as {}".format(a,b)
                    nonlocal count
                    count += 1
                    if y//2 in a: return "<"if y%2 else ">"
                    if y//2 in b: return ">"if y%2 else "<"
                    return "="
                assert B(list(range(x)))==y//2, "{} {} not found in size {}".format(['heavy','light'][y%2], y//2+1, x)
                if count > max_count:
                    max_count = count
            print(x, max_count)
    finally:
        I = orig_I

Dies gibt die ungünstigste Anzahl von Wägungen für einen bestimmten Satz nach dem Testen mit jeder Kombination aus Münze und schlechtem Gewicht (schwer oder leicht) aus.

Hier ist die Testausgabe für Sätze von bis zu 125:

>>> test(150)
3 2
4 2
5 3
6 3
7 3
8 3
9 3
10 3
11 3
12 3
13 3
14 4
15 4
16 4
17 4
18 4
19 4
20 4
21 4
22 4
23 4
24 4
25 4
26 4
27 4
28 4
29 4
30 4
31 4
32 4
33 4
34 4
35 4
36 4
37 4
38 4
39 4
40 4
41 5
42 5
43 5
44 5
45 5
46 5
47 5
48 5
49 5
50 5
51 5
52 5
53 5
54 5
55 5
56 5
57 5
58 5
59 5
60 5
61 5
62 5
63 5
64 5
65 5
66 5
67 5
68 5
69 5
70 5
71 5
72 5
73 5
74 5
75 5
76 5
77 5
78 5
79 5
80 5
81 5
82 5
83 5
84 5
85 5
86 5
87 5
88 5
89 5
90 5
91 5
92 5
93 5
94 5
95 5
96 5
97 5
98 5
99 5
100 5
101 5
102 5
103 5
104 5
105 5
106 5
107 5
108 5
109 5
110 5
111 5
112 5
113 5
114 5
115 5
116 5
117 5
118 5
119 5
120 5
121 5
122 6
123 6
124 6
125 6

Die Haltepunkte liegen genau dort, wo Sie es erwarten würden, zwischen (3^k - 1)/2und (3^k + 1)/2.

Blckknght
quelle