Schreiben Sie ein Programm, um ein 2-D-Diagramm eines Knotens auf der Grundlage der Knotenstruktur zu zeichnen. Ein Knoten ist genau das, wonach es sich anhört: eine Seilschleife, die festgebunden ist. In der Mathematik zeigt ein Knotendiagramm, wo sich ein Stück Seil über oder unter sich kreuzt, um den Knoten zu bilden. Einige beispielhafte Knotendiagramme sind unten dargestellt:
Es gibt einen Bruch in der Linie, in der sich das Seil kreuzt.
Eingabe: Die Eingabe, die den Knoten beschreibt, ist ein Array von ganzen Zahlen. Ein Knoten, bei dem sich das Seil n- mal kreuzt, kann als Array von n ganzen Zahlen mit einem Wert im Bereich [0, n-1] dargestellt werden. Lassen Sie uns dieses Array nennen K .
Um das Array zu erhalten, das einen Knoten beschreibt, nummerieren Sie jedes der Segmente 0 bis n-1. Segment 0 sollte zu Segment 1 führen, was zu Segment 2 führen sollte, was zu Segment 3 führen sollte, und so weiter, bis sich Segment n-1 zurückzieht und zu Segment 0 führt. Ein Segment endet, wenn ein anderes Seilsegment darüber läuft ( durch einen Zeilenumbruch im Diagramm dargestellt). Nehmen wir den einfachsten Knoten - den Kleeblattknoten. Nachdem wir die Segmente nummeriert haben, endet Segment 0, wenn Segment 2 darüber läuft. Segment 1 endet, wenn Segment 0 darüber läuft. und Segment 2 endet, wenn Segment 1 es überquert. Somit ist das Array, das den Knoten beschreibt, [2, 0, 1]. Im allgemeinen Segment x beginnt , wo Segment x-1 mod n aufhörte und endet in dem Segment K [x] kreuzt es.
Das folgende Bild zeigt Knotendiagramme mit beschrifteten Segmenten und den entsprechenden Arrays, die den Knoten beschreiben.
Die oberen drei Diagramme sind echte Knoten, während die unteren drei Seilschlaufen sind, die sich selbst kreuzen, aber nicht wirklich geknüpft sind (aber immer noch entsprechende Codes haben).
Ihre Aufgabe ist es, eine Funktion zu schreiben, die ein Array von ganzen Zahlen K (man könnte es auch anders nennen) verwendet, die einen Knoten (oder eine Seilschleife, die nicht wirklich geknüpft ist) beschreibt und das entsprechende Knotendiagramm wie oben beschrieben erzeugt Beispiele. Wenn Sie können, geben Sie eine unbenutzte Version Ihres Codes oder eine Erklärung an und stellen Sie auch Beispielausgaben Ihres Codes bereit. Derselbe Knoten kann häufig auf mehrere verschiedene Arten dargestellt werden. Wenn jedoch das Knotendiagramm, das Ihre Funktionsausgaben erfüllen, die Eingabe als eine der möglichen Darstellungen enthält, ist Ihre Lösung gültig.
Das ist Code-Golf, also gewinnt der kürzeste Code in Bytes. Die Linie, die das Seil darstellt, kann eine Dicke von 1 Pixel haben, Unter- und Überkreuzungen müssen jedoch deutlich unterscheidbar sein (die Größe des Seilbruchs sollte um mindestens ein Pixel auf beiden Seiten größer sein als die Dicke des Seils). .
Ich werde Antworten positiv bewerten, die auf den Fähigkeiten der eingebauten Knotentheorie beruhen, aber die, die am Ende ausgewählt wurden, können sich nicht auf die Fähigkeiten der eingebauten Knotentheorie stützen.
Alles, was ich über meine Notation weiß: Ich glaube, dass es Wertesequenzen gibt, die keinem Knoten oder Knoten entsprechen. Zum Beispiel scheint es unmöglich zu sein, die Sequenz [2, 3, 4, 0, 1] zu zeichnen.
Angenommen, Sie nehmen eine Kreuzung und folgen ab dieser Kreuzung dem Pfad des Seils in eine Richtung und kennzeichnen jede nicht gekennzeichnete Kreuzung, auf die Sie stoßen, mit immer größeren Integralwerten. Für alternierende Knoten gibt es einen einfachen Algorithmus, um meine Notation in eine solche Kennzeichnung umzuwandeln, und für alternierende Knoten ist es trivial, diese Kennzeichnung in einen Gauß-Code umzuwandeln:
template<size_t n> array<int, 2*n> LabelAlternatingKnot(array<int, n> end_at)
{
array<int, n> end_of;
for(int i=0;i<n;++i) end_of[end_at[i]] = i;
array<int, 2*n> p;
for(int& i : p) i = -1;
int unique = 0;
for(int i=0;i<n;i++)
{
if(p[2*i] < 0)
{
p[2*i] = unique;
p[2*end_of[i] + 1] = unique;
++unique;
}
if(p[2*i+1] < 0)
{
p[2*i+1] = unique;
p[2*end_at[i]] = unique;
++unique;
}
}
return p;
}
template<size_t n> auto GetGaussCode(array<int, n> end_at)
{
auto crossings = LabelAlternatingKnot(end_at);
for(int& i : crossings) ++i;
for(int i=1;i<2*n;i+=2) crossings[i] = -crossings[i];
return crossings;
}
quelle
KnotData
in Mathematica verwenden ...: '(Knot
eingebautes! Anwendungsbeispiel:<< Units`; Convert[Knot, Mile/Hour]
Erträge1.1507794480235425 Mile/Hour
. (Ich denke, das ist lustig, egal ob es wahr oder falsch ist; aber es ist tatsächlich wahr.)Antworten:
GNU Prolog,
622634668 Bytes in Codepage 850Update : In der vorherigen Version des Programms wurden Kreuzungen manchmal so eng, dass sie nicht richtig gerendert wurden, was gegen die Spezifikation verstößt. Ich habe zusätzlichen Code hinzugefügt, um dies zu verhindern.
Update : Anscheinend erfordern PPCG-Regeln zusätzlichen Code, damit das Programm beendet und der Status genau so wiederhergestellt wird, wie er zu Beginn war. Dies macht das Programm etwas länger und fügt ihm kein algorithmisches Interesse hinzu, aber im Interesse der Regelkonformität habe ich es geändert.
Golfprogramm
Verwendung von GNU Prolog, da es eine Constraint-Solver-Syntax hat, die etwas kürzer ist als die arithmetische Syntax von Portable Prolog, wodurch einige Bytes eingespart werden.
Algorithmus
Dies ist eines der Probleme, bei denen es schwierig ist, den Anfang zu machen. Es ist nicht offensichtlich, wie die Form des Knotens aus der angegebenen Notation berechnet werden kann, da Sie nicht wissen, ob Sie die Linie an einer bestimmten Stelle nach links oder rechts biegen sollen (und als solche auch die Notation kann mehrdeutig sein). Meine Lösung bestand effektiv darin, den alten Standby-Modus für das Golfen zu nutzen: Schreiben Sie ein unglaublich ineffizientes Programm, das alle möglichen Ausgaben generiert und dann prüft, ob sie mit den Eingaben übereinstimmen. (Der hier verwendete Algorithmus ist etwas effizienter, da Prolog die gelegentliche Sackgasse beseitigen kann, aber nicht über genügend Informationen verfügt, um die Rechenkomplexität zu verbessern.)
Die Ausgabe erfolgt über das Terminal Art. GNU Prolog scheint einen Einzelbyte-Zeichensatz zu wollen, der mit ASCII konsistent ist, es ist jedoch egal, welcher verwendet wird (da Zeichen mit dem hohen Bit als undurchsichtig behandelt werden). Als Ergebnis habe ich IBM850 verwendet, das weitgehend unterstützt wird und die von uns benötigten Strichzeichnungszeichen enthält.
Ausgabe
Das Programm durchsucht alle möglichen Knotenbilder in der Reihenfolge der Größe ihres Begrenzungsrahmens und wird dann beendet, wenn es den ersten findet. So sieht die Ausgabe aus
m([0]).
:Auf meinem Computer dauerte die Ausführung 290.528 Sekunden. Das Programm ist nicht sehr effizient. Ich ließ es zwei Stunden laufen
m([0,1])
und endete damit:Ungolfed-Version mit Kommentaren
Der Syntax-Textmarker von Stack Exchange scheint das falsche Kommentarsymbol für Prolog zu haben, daher werden in
%
dieser Erklärung anstelle von Kommentaren (die von Prolog verwendet werden)% #
Kommentare verwendet (die natürlich gleichbedeutend sind%
, aber korrekt hervorgehoben werden).quelle