Einführung
Sie sind Biologe und untersuchen die Bewegungsmuster von Bakterien. Ihr Forschungsteam hat ein paar davon in einer Petrischale und Sie zeichnen deren Aktivität auf. Leider sind Sie stark unterfinanziert und können sich keine Videokamera leisten. Machen Sie daher in regelmäßigen Abständen ein Foto des Gerichts. Ihre Aufgabe ist es, ein Programm zu erstellen, das die Bewegungen der Keime aus diesen Bildern nachzeichnet.
Eingang
Ihre Eingaben sind zwei 2D-Zeichenfelder in jedem vernünftigen Format, die aufeinanderfolgende Bilder der Petrischale darstellen. In beiden Arrays stellt das Zeichen ein .
Leerzeichen und O
einen Keim dar (Sie können zwei beliebige Zeichen auswählen, wenn Sie möchten). Außerdem wird das "After" -Array aus dem "Before" -Array erhalten, indem einige Keime um einen Schritt in eine der vier Hauptrichtungen bewegt werden. Insbesondere haben die Arrays die gleiche Form. Die Keime bewegen sich gleichzeitig, sodass sich einer von ihnen in ein Feld bewegen kann, das bereits einen anderen Keim enthielt, wenn er aus dem Weg geht. Es wird garantiert, dass die Ränder des "Vorher" -Arrays nur Leerzeichen enthalten und dass es mindestens einen Keim gibt. Das Folgende ist also ein gültiges Eingangspaar:
Before After
...... ......
.O..O. ....O.
.OO.O. .OO.O.
...... ..O...
Ausgabe
Ihre Ausgabe ist ein einzelnes 2D-Array von Zeichen im selben Format wie die Eingaben. Es wird aus dem "Vorher" -Array erhalten, indem die bewegten Keime >^<v
je nach Bewegungsrichtung durch eines der folgenden ersetzt werden (Sie können hier auch 4 verschiedene Zeichen verwenden). Es kann mehrere mögliche Ausgaben geben, aber Sie sollten nur eine davon angeben. Im obigen Beispiel ist eine mögliche korrekte Ausgabe
......
.v..O.
.>v.O.
......
Unnötige Bewegung ist in der Ausgabe erlaubt und Keime können Plätze tauschen, so dass auch Folgendes gilt:
......
.v..v.
.>v.^.
......
Regeln und Wertung
Sie können ein vollständiges Programm oder eine Funktion schreiben. Die niedrigste Byteanzahl gewinnt, und Standardlücken sind nicht zulässig.
Ich bin an relativ effizienten Algorithmen interessiert, aber ich möchte das Brute Forcing nicht ganz verbieten. Aus diesem Grund gibt es einen Bonus von -75% für die Lösung des letzten Testfalls innerhalb von 10 Minuten auf einer modernen CPU (ich kann die meisten Lösungen nicht testen, daher vertraue ich Ihnen hier nur). Haftungsausschluss: Ich weiß, dass ein schneller Algorithmus existiert (Suche nach "Disjoint Paths Problem"), habe ihn aber nicht selbst implementiert.
Zusätzliche Testfälle
Before
......
.O..O.
..OO..
......
After
......
..O...
...OO.
..O...
Possible output
......
.>..v.
..vO..
......
Before
.......
.OOOOO.
.O..OO.
.OO..O.
.OOOOO.
.......
After
.......
..OOOOO
.O...O.
.O...O.
.OOOOOO
....O..
Possible output
.......
.>>>>>.
.O..>v.
.Ov..v.
.O>>v>.
.......
Before
..........
.OOO..OOO.
.OOOOOOOO.
.OOO..OOO.
..........
After
..O.......
.OOO..O.O.
..OOOOOOOO
.O.O..OOO.
.......O..
Possible output
..........
.>^O..O>v.
.^O>>>vO>.
.O>^..>vO.
..........
Before
............
.OO..OOOOOO.
.OO......OO.
...OOOOOO...
.O.OOOOOO.O.
...OOOOOO...
.OOOOOOOOOO.
............
After
..........O.
.OO..OOOOO..
.O...O...O..
.O.OOOOOOO..
.O.OOOOOO..O
...OO..OO...
....OOOOOOOO
.OOO........
Possible output
............
.OO..v<<<<^.
.v<......^<.
...OOO>>>...
.O.OOO^OO.>.
...OOv^OO...
.vvvO>>>>>>.
............
Before
................
.OOOOOO.OOOOOOO.
..OO..OOOOOOOOO.
.OOO..OOOO..OOO.
..OOOOOOOO..OOO.
.OOOOOOOOOOOOOO.
................
After
................
..OOOOO.OOOOOOOO
..OO..OOOOOOOOO.
..OO..OOOO..OOOO
..OOOOOOOO..OOO.
..OOOOOOOOOOOOOO
................
Possible output
................
.>>>>>v.>>>>>>>.
..OO..>>^>>>>>v.
.>>v..OOO^..OO>.
..O>>>>>>^..OOO.
.>>>>>>>>>>>>>>.
................
Before
..............................
.OOO.O.O.....O.....O.O.O..O...
..OOO.O...O..OO..O..O.O.......
.....O......O..O.....O....O...
.O.OOOOO......O...O..O....O...
.OO..O..OO.O..OO..O..O....O...
..O.O.O......OO.OO..O..OO.....
..O....O..O.OO...OOO.OOO...O..
.....O..OO......O..O...OO.OO..
........O..O........OO.O.O....
..O.....OO.....OO.OO.......O..
.O.....O.O..OO.OO....O......O.
..O..OOOO..O....OO..........O.
.O..O...O.O....O..O....O...OO.
....O...OO..O.......O.O..OO...
........O.O....O.O....O.......
.OO.......O.OO..O.......O..O..
....O....O.O.O...OOO..O.O.OO..
.OO..OO...O.O.O.O.O...OO...O..
..............................
After
..............................
.OOOOO.......OO.....O..O......
...OO..O...O...O....OO....O...
....O.O......O..OO...OO...O...
.OO.OOOO......OO..O..O........
O.O.OO..O..O..O..OO...O...OO..
.OO.....O....OO.O..O.OO.O.....
......O.....O.....OOO.OO...O..
....O..OOOO..O..O..O.O.O.OO...
..O......O.O........O...O.O...
.O.....OOO.....OO.OO...O...O..
.......OOO..O.O.O...........O.
.O...O.....O...OOOO..O.O....O.
.O..O.O..O.....O......O....OO.
....O..O..O.O......O.....O....
........OOO....O......O..O....
.OO......O..OO..OOO.....O..O..
..O.O....OO..O...OO...O...OO..
.O..OO....O..O...O.O.O.OO.....
..............O............O..
Possible output
..............................
.OOO.O.v.....>.....>.v.O..v...
..>>^.v...>..^>..v..O.v.......
.....<......>..>.....O....O...
.O.<O><O......O...O..O....v...
.<O..O..v<.O..O^..O..>....>...
..<.^.v......OO.O^..>..<O.....
..^....v..v.Ov...>>^.<OO...O..
.....<..OO......O..O...Ov.v<..
........>..O........O^.v.^....
..^.....Ov.....OO.OO.......O..
.^.....^.^..O>.vO....v......O.
..<..Ov^^..O....><..........O.
.O..O...>.v....O..^....^...OO.
....O...<v..O.......<.^..v<...
........O.O....O.v....O.......
.OO.......<.Ov..O.......O..O..
....O....O.<.^...O^v..O.v.OO..
.O^..<<...O.>.v.>.^...<O...v..
..............................
quelle
>^<v
entspricht einer Bewegung von genau einem Schritt in die jeweilige Richtung.Antworten:
Oktave,
494496 Bytes - 372 Bytes Bonus = 124 BytesEs gibt noch viel zu tun mit dieser Antwort, aber ich wollte die ungelöste Erklärung einholen.
Ich sah dies als ein Problem der Beschränkungszufriedenheit, also ging ich zu meiner bevorzugten Heuristik für die lokale Suche über, Min-Konflikte . Die Idee ist, bei einer Startplatzierung mit jedem Keim in einem erreichbaren Ziel einen zufälligen Keim auszuwählen, der dieselbe Zielzelle wie ein oder mehrere andere Keime belegt, und ihn in eine gültige Zelle zu verschieben, in der bereits ein Minimum an anderen Keimen vorhanden ist. Wiederholen Sie diesen Vorgang so oft, bis die Platzierung dem Ziel entspricht.
Interessanterweise ist nicht garantiert, dass dieser Algorithmus beendet wird (wenn das Ziel nicht erreichbar ist, wird es beispielsweise auf unbestimmte Zeit fortgesetzt), aber wenn er beendet wird, wird garantiert, dass eine gültige Lösung erstellt wird.
Hier ist der Code:
Ausgabe für den letzten Testfall:
Die durchschnittliche verstrichene Zeit auf einem 5 Jahre alten Core i5, der sich für den Bonus qualifiziert, betrug weniger als
9 Sekunden und1 Sekunde *.Ich versuche, dies auf ideone zum Laufen zu bringen, aber ich habe, wie ich glaube, Probleme mit der Art und Weise, wie verschachtelte Funktionen behandelt werden. (Hier ist der nicht funktionierende ideone-Link als Referenz: http://ideone.com/mQSwgZ )Der Code für ideone funktioniert jetzt. Ich musste alle Variablen auf global setzen, was es unnötig machte, sie lokal auszuführen.
* Ich hatte eine Notiz in meiner ungolfed Version, dass einer der Schritte ineffizient war, also habe ich versucht, die Ausführung zu beschleunigen, und für 2 hinzugefügte Bytes beträgt die Ausführungszeit jetzt weniger als eine Sekunde. Die Code- und Beispielausgabe wurde aktualisiert und die Eingabe in ideone wurde auf den letzten Testfall geändert.
quelle
Python, 1171 Bytes - 878,25 Bytes Bonus = 292,75 Bytes
Ideone-Link: http://ideone.com/0Ylmwq
Nimmt im Durchschnitt zwischen 1 und 8 Sekunden im letzten Testfall in Anspruch und qualifiziert sich für den Bonus.
Dies ist meine erste Code-Golf-Einsendung, es ist also wahrscheinlich nicht das beste Programm, das es gibt. Trotzdem war es eine interessante Herausforderung und ich habe es sehr genossen. @Beaker verdient eine Erwähnung, um mich daran zu erinnern, dass heuristische Suchen eine Sache sind. Bevor er seine Lösung veröffentlichte und mich dazu inspirierte, meine zu wiederholen, war meine Brute-Force-Suche zu lang, um für den Bonus im letzten Testfall zu qualifizieren (es lag in der Größenordnung von 69! -Iterationen, was einer 99-stelligen Zahl entspricht). .).
Ich wollte Beakers Lösung nicht direkt kopieren, also entschied ich mich für simuliertes Tempern für meine Suchheuristik. Es scheint langsamer als ein Min-Konflikt für dieses Problem zu sein (wahrscheinlich, weil es sich eher um einen Optimierungsalgorithmus als um einen Algorithmus zur Erfüllung von Einschränkungen handelt), aber es liegt immer noch deutlich innerhalb der 10-Minuten-Marke. Es hatte auch den Vorteil, dass es in Bezug auf den Code ziemlich klein war. Ich habe viel mehr Bytes für die Transformation des Problems aufgewendet als für die Suche nach einer Lösung.
Erläuterung
Meine Lösung ist wahrscheinlich byteweise ziemlich ineffizient, aber ich hatte Probleme damit, mir vorzustellen, wie ich das Problem so lösen soll, wie es ist, und musste es schließlich in ein anderes Problem umwandeln, das für mich leichter zu verstehen war. Ich habe festgestellt, dass es für jede Zelle im Raster vier Möglichkeiten gibt:
Nachdem ich die Daten in diese Klassen zerlegt hatte, konnte ich das Problem weiter transformieren. Mir war sofort klar, dass ich einen Weg finden musste, um einen Keim aus dem Set "vorher aber nicht nachher" in eine Zelle im Set "nachher aber nicht nachher" zu liefern. Außerdem können sich Keime nur um ein Feld bewegen, sodass sie nur dann auf weiter entfernte Zellen einwirken können, wenn sie einen ungebrochenen Pfad von Keimen in diese Zelle "hineinschieben". Dies bedeutete, dass das Problem darin bestand, in einem Graphen X durch Scheitelpunkte getrennte Pfade zu finden, wobei jede Zelle mit einem Keim ein Scheitelpunkt in dem Graphen war und die Kanten benachbarte Zellen darstellten.
Ich habe das Problem gelöst, indem ich zuerst das oben erläuterte Diagramm erstellt habe. Ich habe dann jeden möglichen Pfad von jeder Zelle in Before und jeder Zelle in After aufgezählt und dann jeder Zelle in Before zufällig einen ihrer möglichen Pfade zugewiesen. Schließlich habe ich simuliertes Tempern verwendet, um die potenzielle Lösung halb zufällig zu mutieren, bis ich schließlich eine Lösung gefunden habe, die für keinen der Pfade Konflikte aufweist.
Kommentierte Version
quelle