Erläuterung
Befunge ist ein zweidimensionales Programm, das Stapel verwendet .
Das heißt, um 5 + 6 zu tun, schreiben Sie 56+
, was bedeutet:
56+
5 push 5 into stack
6 push 6 into stack
+ pop the first two items in the stack and add them up, and push the result into stack
(to those of you who do not know stacks, "push" just means add and "pop" just means take off)
Wir können die Nummer jedoch nicht pushen 56
direkt in den Stapel .
Dazu müssen wir 78*
stattdessen schreiben , was das Produkt multipliziert 7
und 8
in den Stapel schiebt.
Einzelheiten
Für jede Zahl aus 1
zun
, eine Zeichenfolge , die nur aus diesen Zeichen finden: 0123456789+-*/:
(Ich würde nicht verwenden %
Modulo.)
Das Ziel besteht darin, die kürzeste Zeichenfolge zu finden, die die Zahl darstellen kann, indem das oben beschriebene Format verwendet wird.
Wenn zum Beispiel die Eingabe ist 123
, dann wäre die Ausgabe 67*9:*+
. Die Ausgabe sollte von links nach rechts ausgewertet werden.
Wenn es mehr als eine akzeptable Ausgabe gibt (z. B. 99*67*+
auch akzeptabel), kann eine beliebige gedruckt werden (kein Bonus für das Drucken aller).
Weitere Erklärung
Wenn Sie immer noch nicht verstehen, wie Sie 67*9:*+
auswerten sollen 123
, finden Sie hier eine ausführliche Erklärung.
stack |operation|explanation
67*9:*+
[6] 6 push 6 to stack
[6,7] 7 push 7 to stack
[42] * pop two from stack and multiply, then put result to stack
[42,9] 9 push 9 to stack
[42,9,9] : duplicate the top of stack
[42,81] * pop two from stack and multiply, then put result to stack
[123] + pop two from stack and add, then put result to stack
TL; DR
Das Programm muss die kürzeste Zeichenfolge finden, die die Eingabe (Zahl) darstellen kann, wobei das oben angegebene Format verwendet wird.
WERTUNG
- Wir haben es bereits in kürzester Zeit geschafft . Diesmal spielt die Größe keine Rolle.
- Für die Sprache Ihrer Wahl muss ein kostenloser Compiler / Interpreter für mein Betriebssystem (Windows 7 Enterprise) verfügbar sein.
- Bonus, wenn Sie den Link zum Compiler / Interpreter angeben (ich bin zu faul).
- Wenn möglich, fügen Sie bitte einen Timer hinzu. Die Ausgabe des Timers ist gültig.
- Die Punktzahl ist die größte
n
in 1 Minute. - Das heißt, das Programm muss die gewünschte Darstellung ausdrucken
1
. - Keine Hardcodierung, außer
0
zu9
.
(mehr) SPEZIFIKATIONEN
- Das Programm ist ungültig, wenn es einen String ausgibt, der länger ist als für eine beliebige Anzahl benötigt.
1/0=ERROR
5/2=2
,(-5)/2=-2
,(-5)/(-2)=2
,5/(-2)=-2
Begriffsklärung
Das -
ist second-top minus top
, was bedeutet, dass es 92-
zurückkehrt 7
.
Auch das /
ist second-top divide top
, was bedeutet , dass die 92/
Renditen 4
.
Beispielprogramm
Lua
Verwendet die Tiefensuche.
local function div(a,b)
if b == 0 then
return "error"
end
local result = a/b
if result > 0 then
return math.floor(result)
else
return math.ceil(result)
end
end
local function eval(expr)
local stack = {}
for i=1,#expr do
local c = expr:sub(i,i)
if c:match('[0-9]') then
table.insert(stack, tonumber(c))
elseif c == ':' then
local a = table.remove(stack)
if a then
table.insert(stack,a)
table.insert(stack,a)
else
return -1
end
else
local a = table.remove(stack)
local b = table.remove(stack)
if a and b then
if c == '+' then
table.insert(stack, a+b)
elseif c == '-' then
table.insert(stack, b-a)
elseif c == '*' then
table.insert(stack, a*b)
elseif c == '/' then
local test = div(b,a)
if test == "error" then
return -1
else
table.insert(stack, test)
end
end
else
return -1
end
end
end
return table.remove(stack) or -1
end
local samples, temp = {""}, {}
while true do
temp = {}
for i=1,#samples do
local s = samples[i]
if eval(s) ~= -1 or s == "" then for n in ("9876543210+-*/:"):gmatch(".") do
table.insert(temp, s..n)
end end
end
for i=1,#temp do
local test = eval(temp[i])
if input == test then
print(temp[i])
return
end
end
samples = temp
end
quelle
56
direkt in den Stapel hineinschieben können, wie können wir dann78
in den Stapel hineinschieben?56
sechsundfünfzig direkt in den Stapel schieben, aber wir können7
sieben und8
acht getrennt in den Stapel schieben .56
in Befunge machst, drückst du die Ziffern , so dass du am Ende einen Stapel hast[5, 6]
. Um die bekommen Nummer 56, müssen Sie schieben7
, dann8
auf den Stapel, und dann multiplizieren sie die Nummer 56 auf dem Stapel zu erhalten.:
macht die Sache viel kniffliger, daher würde ich empfehlen, eine gute Liste von Testfällen86387
Antworten:
In C ++ wird der gesamte Speicher eines Computers in Ihrer Nähe aufgelöst
Erzeugt die kürzeste Zeichenfolge, bei der die Berechnung nirgendwo einen Überlauf einer vorzeichenbehafteten 32-Bit-Ganzzahl verursacht (alle Zwischenergebnisse liegen also im Bereich)
[-2147483648, 2147483647]
Auf meinem System generiert dies eine Lösung für alle Nummern bis einschließlich
483432
30 Sekunden bei Verwendung von 1,8 G Speicher. Noch höhere Zahlen werden die Speichernutzung schnell explodieren. Die höchste Zahl, die ich auf meinem System verarbeiten kann, ist5113906
. Die Berechnung dauert fast 9 Minuten und 24 GB. Wenn es fertig ist, hat es intern eine Lösung für398499338
Werte, etwa 9% aller 32-Bit-Ganzzahlen (positiv und negativ)Benötigt einen C ++ 11 Compiler. Unter Linux kompilieren mit:
Fügen Sie diese
-DINT64
Option hinzu, um einen 64-Bit-Integer-Bereich anstelle von 32-Bit für Zwischenergebnisse zu verwenden (dies beansprucht etwa 50% mehr Zeit und Speicher). Dies erfordert einen eingebauten 128-Bit-Typ. Möglicherweise müssen Sie den gcc-Typ ändern__int128
. Kein Ergebnis, zumindest der Bereich[1..483432]
ändert sich, indem größere Zwischenergebnisse zugelassen werden.Fügen Sie
-DOVERFLOW
als Option hinzu, dass kein größerer ganzzahliger Typ zum Überprüfen auf Überlauf verwendet wird. Dies hat den Effekt, dass ein Überlauf und ein Werteverlauf zugelassen werden.Wenn Ihr System über tcmalloc ( https://github.com/gperftools/gperftools ) verfügt, können Sie eine Verknüpfung mit diesem Programm herstellen, was zu einem Programm führt, das im Allgemeinen etwas schneller ist und etwas weniger Speicher benötigt. Auf einigen UNIX-Systemen können Sie eine Vorabladung verwenden, z
Grundsätzliche Verwendung: Generiere und drucke alle Zahlen bis zum Ziel:
Optionen:
-a
Drucken Sie auch alle Zahlen aus, die beim Ausarbeiten des Ziels generiert wurden-c
Drucken Sie auch alle Zahlen aus, die mit einem "Übertrag" (dup) beginnen.-f
Suchen und drucken Sie die erste Zahl hinter dem Ziel, die nicht generiert wurde-s
Stoppen, wenn das Ziel generiert wird, auch wenn nicht alle Nummern zuvor generiert wurden-S
Wie-s
und-f
in einer automatischen Schleife. Sobald das Ziel generiert wurde, suchen Sie die erste noch nicht generierte Nummer und machen Sie diese zum neuen Ziel-E
Verlasse das Spiel nicht sofort, wenn das Ziel erreicht ist. Beende zuerst alle Saiten der aktuellen Länge-O
Geben Sie die Zeichenfolgen nicht für alle Zahlen bis zum Ziel aus. Nur die Zeichenfolge für das Ziel-o
Zulässige Anweisungen (Standardeinstellung ist+-*/:
-b num
Niedrigstes Literal, das verschoben werden kann (Standardeinstellung0
)-B num
Höchstes Literal, das verschoben werden kann (Standardeinstellung9
)-r num
Das niedrigste erlaubte Zwischenergebnis. Wird verwendet, um Unterlauf zu vermeiden. (Standardeinstellung istINT32_MIN
,-2147483648
-R num
Das höchstzulässige Zwischenergebnis. Wird verwendet, um ein Überlaufen zu vermeiden. (Standardeinstellung istINT32_MAX
,2147483647
-m memory
(nur Linux) Beenden, wenn ungefähr so viel zusätzlicher Speicher zugewiesen wurdeEinige interessante Optionskombinationen:
Generieren Sie alle Zahlen bis zum Ziel und berechnen Sie die kleinste Zahl, die einen längeren Generator benötigt als alle diese Zahlen:
Nur Ziel generieren (-s), nur Ziel drucken (-O)
Ermitteln Sie die höchste Zahl, die in Ihrem System aufgrund von Zeit- und / oder Speicherbeschränkungen generiert werden kann. (Dies führt dazu, dass Ihr System nicht genügend Speicher hat, wenn Sie es laufen lassen. Subtrahieren Sie 1 von der letzten Ausgabe, nach der Sie gesucht haben und die Sie als letzten sicheren Wert sehen ):
Generieren Sie Lösungen, ohne negative Zwischenergebnisse zu verwenden (
30932
ist der erste Wert, der negative Zwischenergebnisse für die kürzeste Zeichenfolge benötigt):Generieren Sie Lösungen, ohne jemals Druck auszuüben
0
(dies scheint nicht zu suboptimalen Lösungen zu führen):Lösungen generieren, einschließlich
a..f (10..15)
:Lösungen ohne dup generieren
:
(addieren,-r0
da negative Zwischenwerte für diesen Fall nie interessant sind)Finden Sie den ersten Wert, der nicht für eine bestimmte Zeichenfolge Länge erzeugt werden kann unter Verwendung von nur
+
,-
,*
und/
:Dies wird in der Tat die ersten Begriffe von https://oeis.org/A181898 generieren , wird jedoch abweichend sein,
14771
da wir eine abschneidende Division verwenden, so dass die Zahl mit einer Zeichenfolge der Länge 13 anstelle der Länge 15 als OEIS-Reihe erfolgen kann erwartet:Anstatt von
Da eine Division ohne Kürzung sinnlos erscheint, kann die OEIS-Reihe besser mit erzeugt werden
Unter der Annahme, dass die Aufteilung unbrauchbar bleibt, gab mir dies 3 zusätzliche Begriffe, bevor ich aus dem Gedächtnis herauskam:
Eine andere Version dieses Programms, die einen Teil der Daten in externen Dateien speichert, fügt 135153107 und 675854293 hinzu, nach denen alle 32-Bit-Ganzzahlen generiert wurden.
befour.cpp
Einige Testfälle:
1: 1: 1
11: 3: 29+
26: 5: 29*8+
27: 3: 39*
100: 5: 19+:*
2431: 9: 56*9*9*1+
3727: 9: 69*7+:*6+
86387: 11: 67*:*1-7*7*
265729: 11: 39*:*:*2/9+
265620: 13: 99*::*6/*7+3*
1921600: 9: 77*:*:*3/
21523360: 9: 99*:*:*2/
57168721: 11: 99*6+:*8-:*
30932: 11: 159*-:4*:*+
quelle
38950002
dein Programm gibt es89*7+:::**1-*
, was ziemlich gut ist, aber du kannst es299*-::*:*+
für kürzer machen. Ich denke, dies bestätigt die Zweifel, die ich über negative Zahlen hatte ...int main(int argc, char const* const* argv)
Ich kenne C nicht besser als der durchschnittliche Joe, aber was ist das? ein const-Zeiger auf einen const-Zeiger auf ein Zeichen? Sollte es nichtchar const *argv[]
so sein (oderchar const **argv
wenn du so hardcore bist)?JavaScript Node Brute Force
Programmdatei bfCodes.js
Laufen unter Windows
cmd.exe
cmd.exe
mit der Verknüpfung und überprüfen Sie, ob die DOS-Eingabeaufforderung mit dem Arbeitsverzeichnis beginntOptimierung
Der Algorithmus durchläuft alle Kombinationen von befungenen Zeichen, beginnend mit einer Code-Zeichenfolge der Länge 1. Stellen Sie sich vor, Sie drehen einen Kilometerzähler zur Basis 15 von der niedrigstwertigen Stelle. Zahlen höherer Ordnung klickten mit zunehmender Langsamkeit umher.
bfCodes
Der generierte Code wird nicht ausgewertet, wenn die Stack-Länge null oder negativ wäre oder mehr als eine Zahl auf dem Stack verbleibt, um die Ausführungsgeschwindigkeit zu optimieren.Das Brute-Force-Problem
Bei einem Codesatz von 15 Zeichen wird die Zeit, die zum Durchlaufen aller Kombinationen einer bestimmten Länge benötigt wird, durch angegeben
Das heißt, wenn Ihr Programm fünfzehnmal schneller läuft als meins, können Sie nur eine zusätzliche Zeichenkette gleichzeitig prüfen. Um zwei weitere Zeichen gleichzeitig zu prüfen, müsste ein Programm 225-mal schneller ausgeführt werden. Die Zeit, die mit einem Brute-Force-Ansatz benötigt wird, steigt exponentiell an, wenn die Länge der Code-Strings zunimmt. Und die Größe einer Zahl gibt notwendigerweise die Anzahl der zu ihrer Erzeugung erforderlichen befunge Bytes an.
Einige Zahlen.
Ungefähre Zeiten zum Generieren einer Codeliste auf einem Windows 7 32-Bit-Notizblock für ganze Zahlen bis zu
Das Erzeugen von Befunge für 3727 (das ist 66 Quadrat plus 6) für sich allein dauerte 1 Stunde 47 Minuten und wurde generiert
578*+:*6+
Optimale Codegenerierung
Das Generieren von Befunge für Zahlen ohne Überprüfung auf kürzeste Längen ist relativ einfach. Unter Verwendung eines rekursiven Algorithmus, der ganzzahlige Quadratwurzeln und Reste verwendete, dauerte die Codierung für Zahlen bis 132 etwa 3 ms anstelle von 28 Sekunden. Sie waren nicht optimal. Aufgrund der Funktionsweise dieses speziellen Algorithmus, der
638:*-:*+
für 3727 in ungefähr 1 ms (anstelle von ungefähr einer Stunde) erzeugt wurde, geschah dies optimal.Das Problem mit der Bereitstellung einer nicht-brute-force-Methode zeigt, dass sie in jedem Fall optimal ist. Viel Glück!
quelle
+-*/
an den inneren Knoten0-9
und:
an den Blättern darstellen muss (und:
nicht ganz links sein darf). Generieren und bewerten Sie daher alle gültigen Bäume der Größe 2 * n + 1 in Schritt n (n beginnt bei 0) und konvertieren Sie sie bei Bedarf in ZeichenfolgenJavaScript
Was kann man mit einem JS-Snippet machen? In meinem Rechner Firefox 64 Bit, 416 in 60 Sekunden
quelle