Suchen Sie anhand einer Liste von Punkten den kürzesten Pfad, der alle Punkte aufruft und zum Ausgangspunkt zurückkehrt.
Das Problem des Handlungsreisenden ist auf dem Gebiet der Informatik bekannt, da es viele Möglichkeiten gibt, es zu berechnen / zu approximieren. Es wurde für sehr große Punktegruppen gelöst, aber einige der größten benötigen viele CPU-Jahre, um fertig zu werden.
Lass dich nicht von der Kartoffel verbrennen.
Hot Potato ist ein Spiel, bei dem 2+ Spieler eine "Kartoffel" im Kreis herumreichen, während Musik spielt. Das Ziel ist, es schnell an den nächsten Spieler weiterzugeben. Wenn Sie die Kartoffel halten, während die Musik aufhört, sind Sie draußen.
Gegenstand des Hot Potato Salesman ist:
Bei einer Menge von 100 eindeutigen Punkten geben Sie diese Punkte in einer besseren Reihenfolge zurück ( kürzere Gesamtentfernung, wie weiter unten definiert ). Dadurch wird das Problem an den nächsten Spieler "weitergegeben". Sie müssen es verbessern und an die nächste weitergeben usw. Wenn ein Spieler es nicht verbessern kann, sind sie aus und spielen weiter, bis ein Spieler übrig ist.
Damit dies kein "Brute-Force-Me-A-Path" -Wettbewerb ist, gelten folgende Bestimmungen:
Sie können nicht länger als eine Minute brauchen , um die Kartoffel zu überholen. Wenn Sie bis zum Ablauf einer Minute keine kürzere Lösung gefunden und verabschiedet haben, sind Sie unterwegs.
Sie können die Position von mehr als 25 Punkten nicht ändern . Um genau zu sein,
>= 75
müssen sich die Punkte an derselben Position befinden, an der Sie sie erhalten haben. Es spielt keine Rolle, welche Sie ändern möchten, sondern nur den Betrag, den Sie ändern.
Wenn nur noch ein Spieler übrig ist, ist er der Gewinner dieses Spiels und erhält einen Punkt. Ein Turnier besteht aus 5*n
Spielen, wobei n
die Anzahl der Spieler ist. Bei jedem Spiel wird der Startspieler gedreht und die verbleibende Spielerreihenfolge wird gemischt . Der Spieler mit den meisten Punkten am Ende ist der Gewinner des Turniers. Wenn das Turnier mit einem Unentschieden um den ersten Platz endet, wird ein neues Turnier nur mit diesen Teilnehmern gespielt. Dies wird so lange fortgesetzt, bis es kein Unentschieden mehr gibt.
Der Startspieler für jedes Spiel erhält eine Reihe von pseudozufällig ausgewählten Punkten in keiner bestimmten Reihenfolge.
Punkte werden als ein Paar ganzzahliger x,y
Koordinaten in einem kartesischen Gitter definiert. Die Entfernung wird gemessen mit Manhattan - Distanz , |x1-x2| + |y1-y2|
. Alle Koordinaten liegen im [0..199]
Bereich.
Eingang
Die Eingabe erfolgt mit einem einzelnen String-Argument. Es besteht aus 201 durch Kommas getrennten ganzen Zahlen, die die Anzahl der aktuellen Spieler ( m
) und 100 Punkte darstellen:
m,x0,y0,x1,y1,x2,y2,...,x99,y99
Die Reihenfolge dieser Punkte ist der aktuelle Pfad. Die Gesamtentfernung ergibt sich durch Addition der Entfernung von jedem Punkt zum nächsten ( dist(0,1) + dist(1,2) + ... + dist(99,0)
). Vergessen Sie nicht, zurückzukehren, um die Gesamtstrecke zu berechnen!
Beachten Sie, dass m
ist nicht die Anzahl der Spieler, die das Spiel gestartet wird , ist es die Zahl , die noch in sind.
Ausgabe
Die Ausgabe erfolgt wie die Eingabe minus m
; Eine einzelne Zeichenfolge mit durch Kommas getrennten Ganzzahlen, die die Punkte in ihrer neuen Reihenfolge darstellen.
x0,y0,x1,y1,x2,y2,...,x99,y99
Das Steuerungsprogramm wartet nur eine Minute auf die Ausgabe. Beim Empfang der Ausgabe wird Folgendes überprüft:
- der ausgang ist wohlgeformt
- Die Ausgabe besteht aus nur und all den 100 Punkten in dem Eingang
>=75
Die Punkte befinden sich an ihren ursprünglichen Positionen- Die Pfadlänge ist kürzer als der vorherige Pfad
Wenn eine dieser Prüfungen fehlschlägt (oder keine Ausgabe erfolgt), sind Sie aus und das Spiel wird zum nächsten Spieler fortgesetzt.
Steuerungsprogramm
Das Steuerungsprogramm finden Sie unter diesem Link . Das Steuerungsprogramm selbst ist deterministisch und wird mit einem Dummy-Startwert von gebucht 1
. Die Samen, die während der Wertung verwendet werden, sind unterschiedlich. Versuchen Sie also nicht, die Reihenfolge der Züge und die Punktelisten zu analysieren, die sie ausspucken.
Die Hauptklasse ist Tourney
. Wenn Sie dies ausführen, wird ein vollständiges Turnier mit Teilnehmern durchgeführt, die als Argumente angegeben wurden. Es spuckt den Sieger jedes Spiels und eine Bilanz am Ende aus. Ein Beispielturnier mit zwei SwapBots sieht folgendermaßen aus:
Starting tournament with seed 1
(0) SwapBot wins a game! Current score: 1
(1) SwapBot wins a game! Current score: 1
(1) SwapBot wins a game! Current score: 2
(1) SwapBot wins a game! Current score: 3
(0) SwapBot wins a game! Current score: 2
(1) SwapBot wins a game! Current score: 4
(1) SwapBot wins a game! Current score: 5
(1) SwapBot wins a game! Current score: 6
(1) SwapBot wins a game! Current score: 7
(1) SwapBot wins a game! Current score: 8
Final Results:
Wins Contestant
2 (0) SwapBot
8 (1) SwapBot
Wenn Sie jeweils nur ein Spiel testen möchten, können Sie Game
stattdessen die Klasse ausführen . Dies wird ein Spiel mit Spielern in der angegebenen Reihenfolge als Argument ausführen. Standardmäßig wird auch ein Play-by-Play mit dem aktuellen Player und der Pfadlänge gedruckt.
Ebenfalls enthalten sind ein paar Testspieler: SwapBot
, BlockPermuter
, und TwoSwapBot
. Die ersten beiden werden nicht in die Wertungsläufe einbezogen. Sie können sie also während des Tests verwenden und missbrauchen. TwoSwapBot
wird in die Bewertung mit einbezogen, und er ist kein Trottel, also bring dein A-Game mit.
Verschiedenes
Sie können keine Statusinformationen speichern, und jede Runde ist eine separate Ausführung Ihres Programms. Die einzigen Informationen, die Sie in jeder Runde erhalten, sind die Punkte.
Sie können keine externen Ressourcen verwenden. Dies beinhaltet Netzwerkanrufe und Dateizugriff.
Sie können keine Bibliotheksfunktionen verwenden, die zur Lösung / Unterstützung des TSP-Problems oder seiner Varianten entwickelt wurden.
Sie können andere Spieler in keiner Weise manipulieren oder stören.
Sie können das Steuerprogramm oder eingeschlossene Klassen oder Dateien in keiner Weise manipulieren oder stören.
Multithreading ist zulässig.
Eine Einreichung pro Benutzer. Wenn Sie mehr als einen Beitrag einreichen, gebe ich nur den ersten Beitrag ein. Wenn Sie Ihren Beitrag ändern möchten, bearbeiten / löschen Sie das Original.
Das Turnier läuft unter Ubuntu 13.04 auf einem Computer mit einer i7-3770K-CPU und 16 GB RAM. Es wird nicht in einer VM ausgeführt. Alles, was ich als böswillig empfinde, disqualifiziert sofort den aktuellen und jeden zukünftigen Beitrag, den Sie einreichen.
Alle Eingaben müssen über die Kommandozeile mit kostenloser ( wie in Bier ) Software ausgeführt werden können. Wenn ich Probleme beim Kompilieren / Ausführen Ihres Eintrags habe, bitte ich um Hilfe in den Kommentaren. Wenn Sie nicht antworten oder ich es letztendlich nicht zum Laufen bringen kann, wird es disqualifiziert.
Ergebnisse (22 Mai 2014)
Neue Ergebnisse liegen vor! UntangleBot hat die Konkurrenz ziemlich gut geschlagen. TwoSwapBot schaffte sieben Siege und SANNbot erzielte ebenfalls einen Sieg. Hier ist ein Anzeiger und ein Link zur Rohausgabe :
Wins Contestant
22 (2) ./UntangleBot
7 (0) TwoSwapBot
1 (5) SANNbot.R
0 (1) BozoBot
0 (3) Threader
0 (4) DivideAndConquer
Wie steht es nun , UntangleBot hat das Häkchen gewonnen. Lassen Sie sich davon jedoch nicht entmutigen, da ich das Turnier mit mehr Teilnehmern leiten und die akzeptierte Antwort entsprechend ändern werde.
quelle
Antworten:
UntangleBot (ehemals NiceBot)
Ein C ++ 11-Bot, der zwei Strategien verwendet.
Zuerst wird versucht, den Pfad nach Möglichkeit zu "entwirren", indem Schnittpunkte zwischen Pfaden erkannt werden, die näher als 25 Punkte sind (da das Entwirren das Ändern aller dazwischen liegenden Punkte impliziert).
Wenn die erste Strategie fehlschlägt, werden die Punkte nach dem Zufallsprinzip ausgetauscht, um bessere Entfernungen zu finden, bis ein besserer Pfad gefunden wurde.
Dieser Bot schlägt durchweg TwoSwapBot mit einem ungefähren Verhältnis von fünf Siegen für einen Verlust in meinen Testturnieren.
quelle
SANNbot
(ein simulierter Annealing Bot in R )
Sollte mit angerufen werden
Rscript SANNbot.R
.Die Idee ist relativ einfach: Jede Runde ist ein "Abkühlungsschritt" eines simulierten Temperns mit der Anzahl der Spieler, die noch im Spiel sind, als "Temperatur" (geändert um die aktuelle Distanz über 12000, dh ungefähr die anfängliche Distanz). Der einzige Unterschied zu einem richtigen simulierten Tempern ist, dass ich überprüft habe, dass ich nicht mehr als 25 Elemente permutiere. Wenn ich 20 Züge verbraucht habe, aber die resultierende Sequenz mehr wert ist als die anfängliche, dann fängt sie wieder von vorne an.
quelle
java Tourney "java Swapbot" "Rscript SANNbot.R"
und es schien zu funktionieren.u
Check-Limits überschreite, passiert dies nicht (und es funktioniert viel besser). Obwohl Ihr Code ziemlich einfach zu sein scheint , kenne ich die Macken von R nicht und kann daher nicht sagen, ob die Logik falsch ist. (Die neueste Version des Controllers gibt Meldungen darüber aus, warum ein Bot beim Laufen ausgehtGame
, sodass das Problem möglicherweiseBozoBot
Verwendet die komplexe Logik hinter Bozosort , um einen besseren Weg zu finden. Es sieht aus wie das.
BozoBot wurde jetzt mit Multithreading verbessert ! Vier Schergen jonglieren nun ziellos mit Punkten, bis sie auf eine Verbesserung stoßen. Der erste, der eine Lösung findet, bekommt einen Cookie!Anscheinend scheitere ich beim Multithreading.
quelle
new Thread(new Minion()).start()
TwoSwapBot
Bei einem Upgrade auf
SwapBot
sucht dieser Typ nach jedem Swap-Paar. Zunächst prüft er, ob ein einzelner Swap den Pfad verkürzt. Wenn dies der Fall ist, wird es sofort zurückgegeben. Wenn nicht, prüft er jeden, ob ein anderer Swap ihn verkürzt. Wenn nicht, stirbt er einfach.Während der Pfad noch halb zufällig ist, kehrt er normalerweise nach etwa 100 ms zurück. Wenn er jeden 2-Swap (ungefähr 25 Millionen) überprüfen muss, dauert es ungefähr 20 Sekunden.
Zum Zeitpunkt der Einreichung schlug dies alle anderen Teilnehmer in Testrunden.
quelle
Einfädler
Dieser Bot
410 Teile von2510 Punkten aufDie Idee ist, die beste Verbesserung des Pfades zu finden, damit die anderen Bots mit ihrer Logik scheitern.
quelle
println
,print
um die neue Zeile am Ende Ihrer Ausgabe zu entfernen. Sonst stürzt es ab.println
zuprint
und dynamisiert die Threadanzahl. Es beginnt jetzt mit 10 Threads ...Teilen und Erobern + Gieriger Bot
HINWEIS: Ich habe mir Ihren Code angesehen
Game
, der Folgendes in Game.parsePath enthält:Es gibt jedoch keinen
catch(NumberFormatException)
Block, sodass Ihr Programm wahrscheinlich abstürzt, wenn ein Player-Programm eine Zeichenfolge ausgibt (wie am Ende dermain
Methode meines Programms gezeigt ). Ich rate Ihnen, dies zu beheben, da Programme Ausnahmen, Stack-Traces oder ähnliches ausgeben können. Kommentieren Sie andernfalls diese Zeile in meinem Programm aus, bevor Sie es ausführen.Zurück zum Thema
Diese Implementierung (in Java) teilt die Liste der Punkte in Stücke von 25 auf, die zufällig auf der Liste verteilt sind. Anschließend werden Threads erstellt, um den Pfad zwischen den Punkten in jedem Block zu verkürzen (daher "Teilen und Erobern"). Der Haupt-Thread überwacht die anderen und stellt sicher, dass die kürzeste Lösung innerhalb des Zeitlimits angezeigt wird. Wenn ein Thread mit oder ohne Lösung stirbt, startet er einen anderen Thread auf einem anderen Block.
Jeder Thread verwendet den "gierigen" Algorithmus, der an einem zufälligen Punkt beginnt, zum nächsten Punkt geht und sich wiederholt, bis alle Punkte abgedeckt sind (daher "gierig").
Anmerkungen
Einfach kompilieren und
java DivideAndConquer.class
ausführen.quelle
<200
Token vorhanden sind, bevor es versucht, sie zu analysieren. Trotzdem ist es besser, es zu überprüfen.)
Zeile 19 hinzufügen . ändern ,substr
umsubstring
auf 38; Initialisiereidx
etwas in derrun()
Methode.