Der Kassiereralgorithmus ist ein Algorithmus zum Ändern der Mindestanzahl von Münzen, der für die meisten Währungssysteme recht gut geeignet ist. Wie die meisten gierigen Algorithmen ist es jedoch nicht ohne Mängel. Wenn ein Währungssystem nur richtig (oder nur falsch) eingerichtet ist, gibt es bestimmte Werte, bei denen der Algorithmus des Kassierers die optimale Änderung nicht findet.
Nehmen Sie das folgende Beispiel:
Wir haben 4, 3 und 1 Münzen. Wir wollen 6 ¢ machen.
Der Kassiereralgorithmus wählt zunächst so viele der größten Münzen aus (eine 4 ¢ zum Starten) und subtrahiert und wiederholt diese. Dies ergibt eine 4 ¢ Münze und zwei 1 ¢ Münzen für insgesamt 3 Münzen.
Leider gibt es für den Algorithmus eine Möglichkeit, mit nur zwei Münzen 6 ¢ zu machen (zwei 3 ¢ Münzen).
Ein Änderungssystem wird als kanonisch betrachtet, wenn der Algorithmus des Kassierers für alle ganzzahligen Werte die optimale Anzahl von Münzen findet.
Aufgabe
Ihre Aufgabe besteht darin, ein System als ungeordneten Container oder sortierten Container mit ganzen Zahlen zu betrachten, die Münzwerte darstellen, und einen Wahrheitswert auszugeben, wenn die Systemeingabe kanonisch und ansonsten falsch ist.
Ihr Programm sollte für alle Systeme funktionieren, die einen beliebigen Wert erzeugen können. (dh alle Systeme haben eine 1 ¢ Münze)
Das ist Code Golf Least Bytes Wins.
Testfälle
Diese Liste ist keineswegs vollständig, Ihr Programm sollte für alle gültigen Eingaben funktionieren
1, 3, 4 -> 0
1, 5, 10, 25 -> 1
1, 6, 10, 25 -> 0
1, 2, 3 -> 1
1, 8, 17, 30 -> 0
1, 3, 8, 12 -> 0
1, 2, 8, 13 -> 0
1, 2, 4, 6, 8 -> 1
quelle
25, 9, 4, 1
(aus diesem math.SE-Beitrag ) zu machen - obwohl jede Münze größer ist als die Summe der kleineren,25, 4, 4, 4
schlägt der Nichtgierige den Gierigen25, 9, 1, 1, 1
.9, 4, 1
->4, 4, 4
besser ist als9, 1, 1, 1
ein genaueres Beispiel.Antworten:
Haskell,
948782 BytesBei dieser Lösung wird eine Funktion definiert
j
, die den Algorithmus des Kassierers ausführt und angibt, wie viele Münzen der Kassierer verwendet hat. Wir überprüfen dann bis zu zweimal die größte Zahl in der Liste, vorausgesetzt, das System ist für alle vorherigen Zahlen kanonisch und es ist die richtige Wahl, die größtmögliche Münze zu nehmen.Diese Lösung setzt voraus, dass die Eingabe sortiert ist.
Proof-Checking bis zum Doppelten der größten Zahl ist ausreichend: Nehmen Sie an, dass das System für eine bestimmte Zahl nicht kanonisch ist
i
, und lassen Siek
die größte Zahl in der Liste nicht größer als seini
. davon ausgehen,i >= 2k
und das System ist kanonisch für alle Zahlen kleiner alsi
.Gehe
i
davon aus, dass die Münze keine Münze enthältk
. Wenn wir eine der Münzen wegwerfen, muss die neue Münzsumme größerk
und kleiner sein alsi
- aber der Kassiereralgorithmus für diese Zahl würde diek
Münze verwenden -, und daher kann dieser Münzsatz durch einen gleichen Münzsatz ersetzt werden enthält die Münzek
, und daher gibt es eine Reihe von Münzen, die die Münzek
für die Zahl enthalteni
, und durch Induktion gibt der Algorithmus des Kassierers die optimale Auswahl zurück.Dieses Argument zeigt wirklich, dass wir nur die Summe der beiden größten Elemente prüfen müssen - aber es ist länger, dies zu tun.
Edit: fünf Bytes weniger dank Ørjan Johansen!
quelle
let
anstelle von verwendenwhere
. Sie können es entweder als|let ...
Pattern Guard nachf s
oder innerhalb des Listenverständnisses einfügen.j i=last$0:[1+j(i-k)|k<-s,k<i]
.Pyth,
1815 BytesTestsuite
Eine andere Art von roher Gewalt. Dies beginnt mit der Bildung aller Münzsammlungen mit jeweils bis zu k, wobei k die größte Münze ist, die als letzte Münze angenommen wird. Ich glaube, dies reicht immer aus, um zwei Sätze Münzen mit der gleichen Summe zu bilden, einen gierigen und einen kürzeren, wenn ein solches Paar existiert.
Ich finde dann so ein Paar wie folgt:
Die Teilmengen werden in aufsteigender Reihenfolge und lexikografisch nach sekundärer Position in der Eingabe generiert. Gruppieren Sie die Münzsammlungen stabil nach ihren Summen. Jede Münzsammlung wird in absteigender Reihenfolge generiert, sodass die gierige Lösung genau dann das erste Element der Gruppe ist, wenn die gierige Lösung optimal ist, und lexikografisch das letzte Element der Gruppe. So finden wir die gierige Lösung und filtern nach einem Index ungleich Null in der Gruppe. Wenn der Münzsatz kanonisch ist, wird dadurch alles herausgefiltert, sodass wir das Ergebnis und die Ausgabe einfach logisch negieren.
Erläuterung:
quelle
/opt/tryitonline/bin/pyth: line 5: 28070 Killed ... Exit code: 137
bei TIO mit getötet wird ? Einfach zu wenig Speicher?PHP, 323 Bytes
Wie die anderen zählen auch Sie die Münzen bis zur Summe der beiden letzten Elemente im Array
Meine beste und längste Antwort glaube ich> 370 Bytes
Ich gebe nur eine erweiterte Version an, da diese länger ist als meine Antwort zuvor
Erklärung für diese Antwort
Online Version
Setzen Sie all im Array auf false == X
Stellen Sie alle Zahlen in dem Array, das Sie steuern, auf S ein
Gefundene Unterschiede zwischen dem letzten S und dem anderen S oder 0
Beginnen Sie zuletzt mit S im Array
Setze alle Zahlen auf D Where Last S + einer aller Unterschiede
Beginnen Sie überhaupt D
Setzen Sie "T" auf D-Werte im Array
GOTO 5 Wiederhole es mit allen gefundenen DI hab es nicht wirklich im Code
Wenn das nächste Element im Array X enthält, ist dies ein falscher Fall, ansonsten True
Zusätzliche Schritte Unterschied ist in dem Fall in dem Snippet 3 Zwischen 1 und 4 sind 2 X Dies bedeutet, dass Sie das zweite D von Schritt 5 benötigen. Nachdem dieser Wert in diesem Fall 10 alle Fälle wahr sind, konnte ich soweit sehen, dass es eine Beziehung gibt zwischen der Differenz und der Anzahl in dem Array, das Sie steuern, um zu berechnen, wie viel D (Schritt 5) Sie benötigen, um den Punkt zu erhalten, bevor Sie den letzten falschen Fall finden.
Sie setzen mehrere Werte vom letzten Element direkt auf true. Diese Punkte können einen Unterschied machen, um zu entscheiden, ob die Anzahl der gierigen Münzen mit dem nächsten Wert gleich dem Vielfachen des letzten im Array ist. Auf dem anderen Weg können Sie den Feind setzen
Setze den ersten Gegner auf 1 + Last S
Fügen Sie von diesem Punkt an jeden Wert im Array hinzu, um die nächsten Feinde festzulegen
Beginne mit dem letzten Feind Springe zu 2
Wenn Sie jetzt Feinde und wahre Fälle haben, steigt die Wahrscheinlichkeit, dass die Zählungen gleich sein können. Mit mehr D sinkt die Wahrscheinlichkeit.
Plus ? Bytes Vielen Dank an JonathanAllan, der mir falsche Testfälle gegeben hat.
262 Bytes Fast, aber nicht gut genug. 4 falsche Testfälle im Moment
Testfälle [1,16,256] zuvor sollten wahr nach falsch sein
Aufsteigende Reihenfolge des Arrays
Erläuterung
Es sieht so aus, als ob das, was ich in der Tabelle gesehen habe, Werte von [1,2,3,4,5,6] enthält und ich ändere nur das letzte Element bis 9. Für 2to3 und 4to5 erstellen wir den Wert des niedrigeren Werts in der Tabelle Modulo-Berechnung
quelle
", "
wenn Sie aufgespalten könnte","
; Warum trennst du dich, wenn du eine Liste machen könntest? Warum sortierst du, wenn du eine sortierte Liste nehmen könntest? (Ich bin mir auch immer noch nicht sicher, ob die Methode, die Sie verwenden, unfehlbar ist, haben Sie einen Beweis, denn die Literatur, die ich durchgesehen habe, scheint darauf hinzudeuten, dass es schwieriger ist als das, was Ihrer Meinung nach Ihr Code tut.)[1,2,5,11,17]
ist kanonisch. Vielleicht werfen Sie einen Blick auf das Papier, das in meiner Antwort verlinkt ist.JavaScript (ES6), 116
125 130Hierfür muss das Eingabearray in absteigender Reihenfolge sortiert sein. Für jeden Wert von 2N bis 2 (N ist der maximale Münzwert) wird die Anzahl der Münzen aus dem Greedy-Algorithmus ermittelt, und es wird versucht, einen kleineren Satz von Münzen zu finden.
Weniger golfen
Prüfung
quelle
Python,
218 211205 Bytes-1 Byte dank @TuukkaX (ein Leerzeichen könnte zwischen
<3
und gelöscht werdenor
)repl.it
Eingabe in absteigender Reihenfolge.
Schrecklich rohe Gewalt. Jeder Satz einer Münzeinheit und einer anderen Münze ist kanonisch. Bei größeren Sätzen ist der kleinste Fehlerfall, wenn einer existiert, größer oder gleich der drittkleinsten Münze (ich weiß nicht, wie er gleich sein könnte!) Und kleiner als die Summe der beiden größten Münzen - siehe dieses Papier (welches tatsächlich existiert) verweist auf eine andere, gibt aber auch eine O (n ^ 3) -Methode an.
g
zählt die Münzen, die von der gierigen Methode verwendet werden, und die unbenannte Funktion durchläuft die möglichen Kandidaten (tatsächlich von 0 auf eins weniger als das Doppelte der größten Münze, um Bytes zu sparen) und sucht nach einer Sammlung von weniger Münzen, die ebenfalls diesen Betrag ergeben.g
arbeitet mit dem, was ein Kassierer tun würde, nimmt er rekursiv die größte Münze, die kleiner oder gleich dem Betrag ist, der noch aufzufüllen ist,[v for v in c if v<=x][0]
weg und zählt die Anzahl der verwendeten Münzen aufn
.Die unbenannte Funktion gibt 1 zurück, wenn
len(c)
kleiner als 3 ist, und prüft ansonsten, ob dies nicht der Fall ist1-...
und ob Werte im Bereich der Möglichkeitenrange(c[0]*2)))
mit weniger Münzen möglich sindi in range(g(x,c))
, indem von jeder Münze eine Sammlung von so vielen Münzen erstellt wird.c*i
und Untersuchen aller Münzkombinationen, umi
festzustellen,combinations(c*i,i)
ob eine Summe denselben Wert aufweist.quelle
3or
sollte arbeiten.not(...)
mit1-...
Jelly ( Gabel ),
15 bis14 BytesDiese Lösung verwendet die Grenzen für Gegenbeispiele aus diesem Artikel . Dort verwendet der Autor eine enge Grenze für das Gegenbeispiel, aber im Interesse des Golfspiels wird der Bereich der Summe der Münzwerte verwendet, der größer ist und diese Grenze enthält.
Dieses Programm berechnet alle Testfälle in weniger als einer Sekunde auf meinem Computer.
Leider basiert dies auf einem Zweig von Jelly, in dem ich an der Implementierung eines Frobenius-Lösungsatoms gearbeitet habe, sodass Sie es nicht online ausprobieren können.
Verwendungszweck
Die Leistung ist gut und kann alle Testfälle auf einmal in weniger als einer Sekunde lösen.
Erläuterung
quelle
JavaScript (ES6),
144132124122110 ByteErfordert, dass das Array in absteigender Reihenfolge sortiert wird. Verwendet die Beobachtung in dem verlinkten Artikel, dass es, wenn das System nicht kanonisch ist, mindestens einen Wert unter 2a [0] gibt, der weniger Münzen benötigt, wenn er unter Verwendung der nicht verwendeten Münzen aus dem anfänglichen gierigen Algorithmus zerlegt wird.
Bearbeiten: 12 Bytes gespart, indem erkannt wurde, dass ich alle Münzen überprüfen konnte, obwohl ich den Zielwert bereits erreicht hatte. 8 Bytes gespart durch Umschalten der Zwischenausgabe von
[l,b]
auf[b,-l]
; Dies erlaubte mir, das erste Ergebnis direkt als Parameter des zweiten Aufrufs zu übergeben, sowie eine kleine Speicherung, die feststellte, ob der zweite Aufruf erfolgreich war. Durch Verschieben der Definition vong
in densome
Rückruf wurden 2 Bytes gespart , sodass ich die Schleifenvariable nicht unnötig zweimal übergeben musste. 12 Bytes gespart, indem ich von meiner rekursiven Hilfsfunktion auf einen Aufruf von umgeschaltet habefilter
(möglich durch meine Zwischenausgangsumschaltung).quelle
Perl, 69 Bytes
Beinhaltet +2 für
-pa
Geben Sie die Münzen in absteigender Reihenfolge auf STDIN. Optional können Sie die
1
Münze weglassen.coins.pl
:Bildet die Anzahl der vom Kassierer-Algorithmus verwendeten Münzen in
@G
Beträgen von 1 bis zum Zweifachen der größten Münze. Für jeden Betrag wird geprüft, ob der Kassenalgorithmus höchstens 1 Münze weniger benötigt, wenn dieser Betrag um 1 Münze verringert wird. Wenn nicht, ist dies ein Gegenbeispiel (oder es gab ein früheres Gegenbeispiel). Ich könnte beim ersten Gegenbeispiel aufhören, aber das braucht mehr Bytes. So ist die zeitliche KomplexitätO(max_coin * coins)
und die räumliche KomplexitätO(max_coin)
quelle