Perfekte Kennzeichen
Ich habe vor ein paar Jahren angefangen, ein kleines Spiel zu machen, während ich herumfuhr: Überprüfen, ob die Nummernschilder in der Nähe "perfekt" sind. Es ist relativ selten, aber aufregend, wenn Sie eine finden.
So prüfen Sie, ob ein Nummernschild perfekt ist:
- Fassen Sie die Zeichen mit A = 1, B = 2, ... Z = 26 zusammen.
- Nimm jeden aufeinanderfolgenden Teil der Ziffern und addiere sie; Multiplizieren Sie jede dieser Summen.
Wenn die Werte in Teil 1 und Teil 2 gleich sind, herzlichen Glückwunsch! Sie haben ein perfektes Kennzeichen gefunden!
Beispiele
License plate: AB3C4F
Digits -> 3 * 4
= 12
Chars -> A + B + C + F
= 1 + 2 + 3 + 6
= 12
12 == 12 -> perfect!
License plate: G34Z7T
Digits -> (3 + 4) * 7
= 49
Chars -> G + Z + T
= 7 + 26 + 20
= 53
49 != 53 -> not perfect!
License plate: 10G61
Digits -> (1 + 0) * (6 + 1)
= 7
Chars -> G
= 7
7 == 7 -> perfect!
Die Herausforderung
Ich habe als Beispiel Nummernschilder der Länge 5 und 6 verwendet, aber diese Prozedur ist für jede Nummernschildlänge gültig. Ihre Herausforderung besteht darin, für eine gegebene Länge N die Anzahl der perfekten Nummernschilder dieser Länge zurückzugeben. Ein gültiges Kennzeichen im Sinne der Herausforderung ist eine beliebige Kombination aus Ziffern 0-9 und Zeichen AZ. Die Platte muss sowohl ein Zeichen als auch eine Ziffer enthalten , um als potenziell perfekt angesehen zu werden. Zu Überprüfungszwecken sind hier die Werte, die ich erhalten habe (obwohl ich nicht 100% über ihre Korrektheit sein kann, hahaha)
N < 2: 0
N = 2: 18
N = 3: 355
N = 4: 8012
Anmerkungen
Wenn es das Problem in Ihrer Sprache irgendwie einfacher macht, können Sie den Anteil perfekter Nummernschilder für ein bestimmtes N auf mindestens 2 signifikante Stellen ausgeben .
N < 2: 0
N = 2: 0.0138888...
N = 3: 0.0076088...
N = 4: 0.0047701...
ODER Sie können den Äquivalentwert mod 256 ausgeben
N < 2: 0
N = 2: 18
N = 3: 99
N = 4: 76
Kürzeste Gewinne!
N
.Antworten:
Python 3.6, 150 Bytes
Ergebnisse:
Ungolfed Version mit Erklärung:
Das Problem besteht darin, einen Baum zu suchen, in dem jede Ebene des Baums einer Position in einer Kennzeichen-Nummer entspricht und jeder Knoten 36 untergeordnete Elemente (10 Ziffern und 26 Buchstaben) aufweist. Die Funktion durchsucht den Baum rekursiv und sammelt dabei die Werte für die Ziffern und Buchstaben.
Golf inklusive, Umwandlung der for-Schleifen in Summen von Generatoren:
Dann die Generatoren kombinieren. Kodieren Sie die Buchstaben von A bis Z als -1 bis -26 und die Ziffern als 0 bis 9. Die Summe wird also zu:
wo args ist:
Der Rest des Golfspiels besteht darin, die Funktion in ein Lambda umzuwandeln, Variablennamen zu verkürzen und Ausdrücke zu vereinfachen.
quelle
n*n*log(n)
oder etwas ähnliches?Dyalog APL,
5756 Bytes(nimmt an
⎕io←0
)a
Matrix aller gültigen Nummernschilder (außer00...0
) codiert mit: 0-9 für Ziffern, 10-35 für Buchstabenb
Bitmaske für Stellen, an denen Ziffern vorkommenc
Bitmaske für die letzte Ziffer in jeder Gruppe aufeinanderfolgender Ziffernquelle
Python 2,
359295 BytesEher lang; Das ist die triviale Lösung. Ich bin zuversichtlich, dass dies korrekt ist, obwohl es nicht mit den Testfällen in der Herausforderung übereinstimmt. Die Lösungen, die ich bekomme, stimmen mit den Antworten von Dada überein.
-64 Bytes dank Vorschlägen von @numbermaniac
quelle
for
; zwischenmap(ord,x)
undif
; und in der letzten Zeile zwischen.join(x)
undfor
. Ich denke, Sie können auch noch mehr sparen, wenn Sie die Funktionen zu Lambdas neu definieren.Python 2 ,
291287276273 BytesProbieren Sie es online!
Ergebnisse:
quelle
Perl 5 , 117 Bytes
116 Byte Code +
-p
Flag.Probieren Sie es online!
Es fühlt sich ziemlich suboptimal an, aber ich habe momentan keine Ideen mehr.
Der Code selbst ist sehr ineffizient, da er jede Permutation von
a..z,0..9
Länge berechnetn
(ca. 1 Sekunden=3
, ca. 15 Sekundenn=4
und ca. 7 Minutenn=5
).Der Algorithmus ist ganz einfach: Berechnet für jede mögliche Platte der Größe
n
(generiert mitglob"{@F}"x$_
- derglob
Operator ist ziemlich magisch)$r*=eval s/./+$&/gr for/\d+/g;
das Produkt jedes Ziffernblocks und$r+=64-ord for/\pl/g
subtrahiert das Gewicht der Buchstaben. Dann erhöhen wir den Zähler,$\
wenn das$r
ist0
(!$r
) und wenn die Platte Zahlen und Buchstaben enthält (/\pl/*/\d/
).$\
wird dank-p
flag implizit am ende gedruckt .Beachten Sie, dass die Zahlen , die ich erhalten sind
n=2 -> 18
,n=3 -> 355
,n=4 -> 8012
,n=5 -> 218153
. Ich bin mir ziemlich sicher, dass dies die richtigen sind, aber ich könnte mich irren. In diesem Fall lass es mich wissen und ich werde diese Antwort löschen.quelle
APL (Dyalog) , 71 Bytes
Voller Programmteil. Eingabeaufforderungen für N. N≥4 erfordern sehr viel Speicher und Rechenaufwand.
Probieren Sie es online!
quelle
Scala, 265 Bytes
Erklärungen:
Anmerkungen :
-64
und-48
werden verwendet , um ein zu transformierenChar
(bzw. Buchstaben und Ziffern) auf seinenInt
Wert ('A' - 64 = 1
,'B' - 64 = 2
...,'9' - 48 = 9
)l.split("[A-Z]").filter(""<)
werden""
Werte entfernt,l
die mit einem Buchstaben beginnen (Beispiel:)"A1".split("[A-Z]") => Array("", 1)
. Es könnte eine bessere und kürzere Lösung gebenTestfälle:
Ergebnisse :
Die Funktion ist ziemlich langsam,
n > 4
da alle Kombinationen generiert werden müssen.quelle
Java,
382365 BytesGolf gespielt
Detailliert
quelle
n
als Eingabe nimmt.int h(String s){int m=0;for(int c:s.toCharArray())m+=c-48;return m;}int g(String t){int d=1,c=0;for(String s:t.split("[^0-9]"))d*=h(s);for(String s:t.split("[^A-Z]"))c+=s.charAt(0)-65;return d==c?1:0;}int f(String t,int n){int m=0;if(t.length()==n)return g(t);for(int d=48;d<58;)m+=f(t+d++,n);for(int c=65;c<91;)m+=f(t+c++,n);return m;}int s(int n){return f("",n);}
( 365 Bytes ) Sie können Ihre aktuelle Version mit dieser vergleichen, um zu sehen, welche Änderungen ich vorgenommen habe (zu viel, um in den Rest dieses Kommentars zu passen). :)GAP , 416 Bytes
Gewinnt nicht mit der Codegröße und bei weitem nicht mit der konstanten Zeit, sondern verwendet Mathematik, um viel zu beschleunigen!
Um das unnötige Leerzeichen zu entfernen und eine Zeile mit 416 Bytes zu erhalten, gehen Sie folgendermaßen vor:
Mein alter "für Windows XP entworfener" Laptop kann
f(10)
in weniger als einer Minute rechnen und in weniger als einer Stunde noch viel weiter gehen:Wie es funktioniert
Angenommen, wir möchten zunächst nur die Anzahl der perfekten Nummernschilder kennen, die zum Muster passen
LDDLLDL
, wobeiL
ein Buchstabe undD
eine Ziffer bezeichnet werden. Angenommen, wir haben eine Listel
von Zahlen,l[i]
die die Anzahl der Möglichkeiten angibt, wie die Buchstaben den Wert angeben könneni
, und eine ähnliche Listed
für die Werte, die wir aus den Ziffern erhalten. Dann ist die Anzahl der perfekten Nummernschilder mit gemeinsamem Werti
geradel[i]*d[i]
, und wir erhalten die Anzahl aller perfekten Nummernschilder mit unserem Muster, indem wir dies über alles summiereni
. Lassen Sie uns die Operation bezeichnen, mit der diese Summe berechnet wirdl@d
.Selbst wenn der beste Weg, um diese Listen zu erhalten, darin bestand, alle Kombinationen und Zählwerte auszuprobieren, können wir dies unabhängig für die Buchstaben und Ziffern tun und dabei
26^4+10^3
Fälle anstelle von26^4*10^3
Fällen betrachten, in denen wir einfach alle Platten durchlaufen, die zum Muster passen. Aber wir können viel besser:l
Ist nur die Liste der Koeffizienten,(x+x^2+...+x^26)^k
wok
ist die Anzahl der Buchstaben, hier4
.In ähnlicher Weise erhalten wir die Anzahl der Möglichkeiten, um eine Summe von Ziffern in einer Folge von
k
Ziffern als die Koeffizienten von zu erhalten(1+x+...+x^9)^k
. Wenn es mehr als ein Lauf von Ziffern ist, müssen wir die entsprechenden Listen mit einer Operation kombinieren ,d1#d2
dass in der Positioni
als Wert die Summe aller ,d1[i1]*d2[i2]
woi1*i2=i
. Dies ist die Dirichlet-Faltung, die nur das Produkt ist, wenn wir die Listen als Koeffizienten von Dirchlet-Reihen interpretieren. Aber wir haben sie bereits als Polynome (endliche Potenzreihen) verwendet, und es gibt keine gute Möglichkeit, die Operation für sie zu interpretieren. Ich denke, dieses Missverhältnis ist Teil dessen, was es schwierig macht, eine einfache Formel zu finden. Verwenden wir es trotzdem für Polynome und verwenden die gleiche Notation#
. Es ist einfach zu berechnen, wenn ein Operand ein Monom ist: wir habenp(x) # x^k = p(x^k)
. Zusammen mit der Tatsache, dass es bilinear ist, ergibt dies eine schöne (aber nicht sehr effiziente) Möglichkeit, es zu berechnen.Beachten Sie, dass
k
Buchstaben einen Wert von höchstens26k
undk
einzelne Ziffern einen Wert von ergeben können9^k
. So werden wir imd
Polynom oft nicht benötigte hohe Potenzen bekommen . Um sie loszuwerden, können wir modulo berechnenx^(maxlettervalue+1)
. Dies beschleunigt erheblich und hilft, obwohl ich es nicht sofort bemerkt habe, sogar beim Golfen, da wir jetzt wissen, dass der Gradd
nicht größer ist als der vonl
, was die Obergrenze im Finale vereinfachtSum
. Wir erreichen eine noch bessere Beschleunigung, wenn wirmod
im ersten Argument vonValue
(siehe Kommentare) eine Berechnung durchführen , und wenn wir die gesamte#
Berechnung auf einer niedrigeren Ebene durchführen , erhalten wir eine unglaubliche Beschleunigung. Aber wir versuchen immer noch, eine legitime Antwort auf ein Golfproblem zu sein.Damit haben wir unser
l
undd
und können daraus die Anzahl der perfekten Kennzeichen mit Muster berechnenLDDLLDL
. Das ist die gleiche Zahl wie für das MusterLDLLDDL
. Generell können wir die Reihenfolge der Ziffernreihen unterschiedlicher Länge nach Belieben ändern,NrArrangements
was die Anzahl der Möglichkeiten ergibt. Und während zwischen den Ziffernfolgen ein Buchstabe stehen muss, sind die anderen Buchstaben nicht festgelegt. DasBinomial
zählt diese Möglichkeiten.Jetzt müssen noch alle möglichen Arten von Lauflängen-Ziffern durchlaufen werden.
r
Läuft durch alle Anzahlen von Läufen,c
durch alle Gesamtzahlen von Ziffern undp
durch alle Partitionen vonc
mitr
Summanden.Die Gesamtzahl der Partitionen, die wir betrachten, ist zwei weniger als die Anzahl der Partitionen
n+1
, und die Partitionsfunktionen wachsen wie folgtexp(sqrt(n))
. Während es also immer noch einfache Möglichkeiten gibt, die Laufzeit zu verbessern, indem die Ergebnisse wiederverwendet werden (indem die Partitionen in einer anderen Reihenfolge durchlaufen werden), müssen wir für eine grundlegende Verbesserung vermeiden, jede Partition einzeln zu betrachten.Schnell rechnen
Beachten Sie das
(p+q)@r = p@r + q@r
. Dies allein hilft nur, einige Multiplikationen zu vermeiden. Zusammen(p+q)#r = p#r + q#r
bedeutet dies jedoch, dass wir durch einfache Addition Polynome kombinieren können, die verschiedenen Partitionen entsprechen. Wir können nicht einfach addieren sie alle, weil wir nach wie vor , mit denen müssen wissen ,l
wir haben@
Mähdreschernahrung, welcher Faktor wir verwenden müssen, und welche#
-extensions sind noch möglich.Lassen Sie uns alle Polynome, die Partitionen entsprechen, mit derselben Summe und Länge kombinieren und bereits die verschiedenen Arten der Verteilung der Längen von Ziffernfolgen berücksichtigen. Anders als ich in den Kommentaren spekuliert habe, muss ich mich nicht um den kleinsten verwendeten Wert oder wie oft er verwendet wird kümmern, wenn ich sicher gehe, dass ich nicht mit diesem Wert verlängere.
Hier ist mein C ++ Code:
Dies verwendet die GNU MP-Bibliothek. Unter Debian installieren
libgmp-dev
. Kompilieren mitg++ -std=c++11 -O3 -o pl pl.cpp -lgmp -lgmpxx
. Das Programm bezieht sein Argument aus stdin. Verwenden Sie für das Timingecho 100 | time ./pl
.Am Ende
a[sum][length][i]
wird die Anzahl der Möglichkeiten angegeben, auf diesum
Ziffern inlength
Läufen die Anzahl angeben könneni
. Während der Berechnung am Anfang derm
Schleife wird die Anzahl der Möglichkeiten angegeben, die mit Zahlen größer als ausgeführt werden könnenm
. Alles beginnt mita[0][0][1]=1
. Beachten Sie, dass dies eine Obermenge der Zahlen ist, die wir benötigen, um die Funktion für kleinere Werte zu berechnen. So konnten wir fast gleichzeitig alle Werte bis zu berechnenn
.Es gibt keine Rekursion, daher haben wir eine feste Anzahl von verschachtelten Schleifen. (Die tiefste Verschachtelungsebene ist 6.) Jede Schleife durchläuft eine Reihe von Werten, die
n
im ungünstigsten Fall linear sind . Wir brauchen also nur Polynomzeit. Wenn wir uns das verschachtelte Element genauer anseheni
und esj
einschleifenextend
, finden wir eine Obergrenze fürj
das FormularN/i
. Das sollte nur einen logarithmischen Faktor für diej
Schleife ergeben. Die innerste Schleifef
(mitsumn
etc) ist ähnlich. Denken Sie auch daran, dass wir mit schnell wachsenden Zahlen rechnen.Beachten Sie auch, dass wir
O(n^3)
diese Nummern speichern .Experimentell erhalte ich diese Ergebnisse auf vernünftiger Hardware (i5-4590S): Benötigt
f(50)
eine Sekunde und 23 MB,f(100)
benötigt 21 Sekunden und 166 MB,f(200)
benötigt 10 Minuten und 1,5 GB undf(300)
benötigt eine Stunde und 5,6 GB. Dies deutet auf eine Zeitkomplexität hin, die besser ist alsO(n^5)
.quelle
n=5
gibt es keine Fall mit einer Folge von zwei Ziffern und zwei einzelnen Ziffern, weil wir dann nicht genug Buchstaben haben, um die Zahlen zu trennen. Dies ist, was die drei äußerenfor
Schleifen tun: Durchlaufen Sie alle nützlichen Partitionen von Zahlen<n
. (Und ich habe gerade festgestellt, dass ich auchn
Ziffern zulasse . Zum Glück zählt eine weitere Optimierung dies als 0).<n/2
, alle Partitionen nützlich sind. Und die verbleibenden Berechnungen benötigen immer noch ihre nicht konstante Zeit. Um zu sehen, was los ist, können SiePrint(p,"\n");
am Anfang des Körpers derfor p...
Schleife hinzufügen . - Ich habe eine Idee für die Verwendung einer Schleife weniger, aber es wird nur die Codegröße helfen.mod
(was schon viel geholfen hat) inValue
ändereValue(d mod x^(1+QuoInt(s(l)-1,i-1)),x^(i-1))
. Das allein ermöglicht es,f(15)
in 80 Sekunden zu berechnen .Pyth, 55 Bytes
quelle