Diese Herausforderung besteht darin, die längste Kette englischer Wörter zu finden, bei der die ersten drei Zeichen des nächsten Wortes mit den letzten drei Zeichen des letzten Wortes übereinstimmen. Sie verwenden ein allgemeines Wörterbuch, das in Linux-Distributionen verfügbar ist und hier heruntergeladen werden kann:
https://www.dropbox.com/s/8tyzf94ps37tzp7/words?dl=0
welches 99171 englische Wörter hat. Wenn es sich bei Ihrem lokalen Linux /usr/share/dict/words
um dieselbe Datei handelt (hat md5sum == cbbcded3dc3b61ad50c4e36f79c37084), können Sie diese verwenden.
Wörter dürfen in einer Antwort nur einmal verwendet werden.
BEARBEITEN: Buchstaben müssen genau übereinstimmen, einschließlich Groß- / Kleinschreibung, Apostrophe und Akzente.
Ein Beispiel für eine gültige Antwort lautet:
idea deadpan panoramic micra craftsman mantra traffic fiche
Was 8 Punkte bringen würde.
Die Antwort mit der längsten gültigen Wortkette gewinnt. Bei einem Gleichstand gewinnt die früheste Antwort. Ihre Antwort sollte die gefundene Wortkette und (natürlich) das Programm, das Sie dafür geschrieben haben, auflisten.
quelle
Antworten:
Java, Heuristik, die den Scheitelpunkt bevorzugt, der den größten Graphen hervorruft:
1825 18551873Der folgende Code wird in weniger als 10 Minuten ausgeführt und findet den folgenden Pfad:
Kernideen
In Approximation der am längsten gerichteten Wege und Zyklen , Bjorklund, Husfeldt und Khanna, Lecture Notes in Computer Science (2004), 222-233, schlagen die Autoren vor, dass in spärlichen Expandergraphen ein langer Weg durch eine gierige Suche gefunden werden kann, die bei jedem auswählt Schritt den Nachbarn des aktuellen Endes des Pfads, der den größten Teilgraphen in G 'überspannt, wobei G' der ursprüngliche Graph ist, bei dem die Eckpunkte im aktuellen Pfad gelöscht sind. Ich bin mir nicht sicher, ob es sich bei einem Graphen um einen Expander-Graphen handelt, aber wir haben es sicherlich mit einem spärlichen Graphen zu tun, und da sein Kern etwa 20000 Scheitelpunkte hat und er nur einen Durchmesser von 15 hat, muss er gut sein Expansionseigenschaften. Also nehme ich diese gierige Heuristik an.
Anhand eines Graphen
G(V, E)
können wir herausfinden, wie viele Eckpunkte von jedem Eckpunkt aus mit Floyd-Warshall in derTheta(V^3)
Zeit oder mit Johnsons Algorithmus in derTheta(V^2 lg V + VE)
Zeit erreichbar sind. Ich weiß jedoch, dass es sich um einen Graphen handelt, der eine sehr große, stark verknüpfte Komponente (SCC) hat, daher gehe ich anders vor. Wenn wir SCCs mit Tarjans Algorithmus identifizieren, erhalten wir auch eine topologische Sortierung für den komprimierten GraphenG_c(V_c, E_c)
, der mit der Zeit viel kleiner sein wirdO(E)
. DaG_c
ein DAG ist, können wir die Erreichbarkeit in berechnenG_c
in derO(V_c^2 + E_c)
Zeit. (Ich habe später festgestellt, dass dies in Übung 26-2.8 der CLR angedeutet ist ).Da der dominierende Faktor in der Laufzeit ist
E
, optimiere ich ihn, indem ich Dummy-Knoten für die Präfixe / Suffixe einfüge. Anstatt also 151 * 64 = 9664 Ränder von Worten endet -res auf Wörter res- Ich habe 151 Kanten von Worten endet -res bis # res # und 64 Kanten aus # res # auf Wörter res- .Und da jede Suche auf meinem alten PC ungefähr 4 Minuten dauert, versuche ich, die Ergebnisse mit früheren langen Pfaden zu kombinieren. Das geht viel schneller und ist meine derzeit beste Lösung.
Code
org/cheddarmonk/math/graph/Graph.java
:org/cheddarmonk/math/graph/MutableGraph.java
:org/cheddarmonk/math/graph/StronglyConnectedComponents.java
:org/cheddarmonk/ppcg/PPCG.java
:quelle
Rubin, 1701
"Del" -> "ersatz's"
( vollständige Sequenz )Der Versuch, die optimale Lösung zu finden, erwies sich zeitlich als zu kostspielig. Warum also nicht zufällige Stichproben auswählen, was wir können und auf das Beste hoffen?
Zunächst
Hash
wird a erstellt, das Präfixe auf vollständige Welten abbildet, die mit diesem Präfix beginnen (z"the" => ["the", "them", "their", ...]
. B. ). Dann wird für jedes Wort in der Liste die Methodesequence
aufgerufen. Es erhält die Wörter, die möglicherweise aus dem folgen könntenHash
, entnimmt ein Beispiel von100
und ruft sich selbst rekursiv auf. Das längste wird genommen und stolz angezeigt. Der Startwert für das RNG (Random::DEFAULT
) und die Länge der Sequenz werden ebenfalls angezeigt.Ich musste das Programm einige Male ausführen, um ein gutes Ergebnis zu erzielen. Dieses besondere Ergebnis wurde mit Samen erzeugt
328678850348335483228838046308296635426328678850348335483228838046308296635426
.Skript
quelle
0.0996
Sekunden.Partitur:
16311662 WörterDie gesamte Sequenz finden Sie hier: http://pastebin.com/TfAvhP9X
Ich habe nicht den vollständigen Quellcode. Ich habe verschiedene Ansätze ausprobiert. Aber hier sind einige Code-Schnipsel, die in der Lage sein sollten, eine Sequenz von ungefähr der gleichen Länge zu erzeugen. Entschuldigung, es ist nicht sehr schön.
Code (Python):
Zuerst eine Vorverarbeitung der Daten.
Dann habe ich eine rekursive Funktion definiert (Tiefensuche).
Das dauert natürlich viel zu lange. Aber nach einiger Zeit fand es eine Sequenz mit 1090 Elementen und ich hörte auf.
Das nächste, was zu tun ist, ist eine lokale Suche. Für jeweils zwei Nachbarn n1, n2 in der Sequenz versuche ich, eine Sequenz zu finden, die bei n1 beginnt und bei n2 endet. Wenn eine solche Sequenz existiert, füge ich sie ein.
Natürlich musste ich das Programm auch manuell stoppen.
quelle
PHP,
Jahre 1742Jahre 1795Ich habe mit PHP rumgespielt. Der Trick besteht definitiv darin, die Liste auf die ungefähr 20.000 zu bringen, die tatsächlich gültig sind, und den Rest einfach wegzuwerfen. Mein Programm macht dies iterativ (einige Wörter, die es in der ersten Iteration wegwirft, bedeuten, dass andere nicht mehr gültig sind).
Mein Code ist schrecklich, er verwendet eine Reihe globaler Variablen, er belegt viel zu viel Speicher (er speichert eine Kopie der gesamten Präfixtabelle für jede Iteration) und es hat buchstäblich Tage gedauert, bis ich mein aktuelles Bestes gegeben habe, aber er verwaltet es immer noch gewinnen - fürs Erste. Es beginnt ziemlich schnell, wird aber mit der Zeit immer langsamer.
Eine offensichtliche Verbesserung wäre die Verwendung eines verwaisten Wortes für Start und Ziel.
Wie auch immer, ich weiß wirklich nicht, warum meine Pastebin-Liste hier in einen Kommentar verschoben wurde. Sie ist zurück als Link zum Pastebin, da ich jetzt meinen Code eingefügt habe.
http://pastebin.com/Mzs0XwjV
quelle
Python:
1702-1704- 1733 WörterIch habe ein Diktat verwendet, um allen Wörtern alle Präfixe zuzuordnen
Kleine Verbesserung bearbeiten : Entfernen aller
useless
Wörter am Anfang, wenn ihre Suffixe nicht in der Präfixliste enthalten sind (wäre natürlich ein Endwort)Nehmen Sie dann ein Wort in die Liste und durchsuchen Sie die Präfixkarte wie einen Baumknoten
Das Programm benötigt eine Reihe von Wörtern, um zu wissen, wann aufhören kann, wie
1733
in der Methode zu findencheckForNextWord̀
Das Programm benötigt den Dateipfad als Argument
Nicht sehr pythonisch, aber ich habe es versucht.
Es dauerte weniger als 2 Minuten , diese Sequenz zu berechnen: volle Leistung :
quelle
Ergebnis:
2495001001Hier ist mein Code:
Bearbeiten: 1001:
http://pastebin.com/yN0eXKZm
Bearbeiten: 500:
quelle
Mathematica
14821655Etwas zu beginnen ...
Links sind die Kreuzungspräfixe und -suffixe für Wörter.
Kanten sind alle gerichteten Links von einem Wort zu anderen Wörtern:
Finden Sie einen Weg zwischen "heilen" und "Lust".
Ergebnis (1655 Wörter)
quelle
Python, 90
Zuerst räume ich die Liste manuell auf, indem ich alle lösche
das kostet mich höchstens 2 punkte, weil diese wörter nur am anfang oder am ende der kette stehen können, aber es reduziert die wortliste um 1/3 und ich muss mich nicht mit unicode auseinandersetzen.
Als nächstes konstruiere ich eine Liste aller Vor- und Nachsetzzeichen, finde die Überlappung und verwerfe alle Wörter, es sei denn, sowohl das Vor- als auch das Nachsetzzeichen befinden sich im Überlappungssatz. Auch dies spart höchstens 2 Punkte meiner maximal erreichbaren Punktzahl, reduziert jedoch die Wortliste auf ein Drittel der ursprünglichen Größe (versuchen Sie, Ihren Algorithmus für eine mögliche Beschleunigung auf der short_list auszuführen), und die verbleibenden Wörter sind eng miteinander verbunden (mit Ausnahme von 3) -Letterswörter, die nur mit sich selbst verbunden sind). Tatsächlich kann fast jedes Wort von jedem anderen Wort über einen Pfad mit durchschnittlich 4 Kanten erreicht werden.
Ich speichere die Anzahl der Verknüpfungen in einer Adjazenzmatrix, die alle Operationen vereinfacht und es mir ermöglicht, coole Dinge wie n Schritte vorauszusehen oder Zyklen zu zählen ... zumindest theoretisch, da es ungefähr 15 Sekunden dauert, die Matrix zu quadrieren, die ich eigentlich nicht tue Dies während der Suche. Stattdessen beginne ich mit einem zufälligen Präfix und gehe nach dem Zufallsprinzip umher. Entweder wähle ich ein einheitliches Ende und bevorzuge diejenigen, die häufig vorkommen (wie '-ing') oder diejenigen, die seltener vorkommen.
Alle drei Varianten saugen gleich und produzieren Ketten im Bereich von 20 bis 40, aber zumindest ist es schnell. Schätze, ich muss doch Rekursion hinzufügen.
Ursprünglich wollte ich etwas Ähnliches versuchen , dies aber da dies ein gerichteter Graph mit Zyklen, keine der Standard - Algorithmen für topologische Sortierung, Longest Path, Größter Eulersche Pfad oder Chinesisch Postman Problem arbeiten , ohne schwere Modifikationen.
Und nur weil es gut aussieht, ist hier ein Bild der Adjazenzmatrix M, M ^ 2 und M ^ unendlich (unendlich = 32, ändert sich danach nicht) mit weißen Einträgen ungleich Null
quelle