Besuche Punkte auf einer Zahlengeraden, während du die Kosten minimierst, die nicht mit der Entfernung zusammenhängen

18

Ich benötige Hilfe bei diesem ACM-ICPC-Problem. Meine aktuelle Idee ist es, dies als Problem mit dem kürzesten Weg zu modellieren, das unter der Problemstellung beschrieben wird.

Problem

Es gibt N = 1000Kernabfallbehälter befindet sich entlang einer 1-D - Nummer Linie an unterschiedlichen Positionen aus -500,000 to 500,000, mit der Ausnahme x=0. Eine Person muss alle Mülleimer einsammeln. In jeder Sekunde, in der ein Abfallbehälter nicht eingesammelt wird, strahlt er 1 Einheit Strahlung aus. Die Person beginnt bei x = 0und kann die 1Einheit jede Sekunde bewegen , und das Sammeln des Abfalls dauert vernachlässigbar lange. Wir wollen die minimale Menge an Strahlung finden, die beim Sammeln aller Behälter freigesetzt wird.

Beispiel Input:

4Container befinden sich bei [-12, -2, 3, 7].

Die beste Reihenfolge, um diese Container zu sammeln, ist [-2, 3, 7, -12]eine minimale Emission von 50Einheiten. Erklärung: Die Person geht -2in 2 Sekunden zu und während dieser Zeit wird 2 unitsStrahlung abgegeben. Dann geht er zu 3(distance:), 5so dass der Lauf 2 + 5 = 7Strahlungseinheiten freigesetzt hat . Er braucht 4mehr Sekunden, um dorthin zu gelangen, x = 7wo das Fass 2 + 5 + 4 = 11Einheiten abgegeben hat . Er braucht 19Sekunden, um dorthin zu gelangen, x = -12wo das Fass 2 + 5 + 4 + 19 = 30Einheiten abgegeben hat . 2 + 7 + 11 + 30 = 50, das ist die Antwort.

Anmerkungen

Es gibt eine offensichtliche O(N!)Lösung. Ich habe mich jedoch mit gierigen Methoden befasst, wie zum Beispiel dem nächstgelegenen oder dem nächstgelegenen Cluster, aber diese haben nicht funktioniert.

Ich habe über dieses Problem eine ganze Weile nachgedacht und es als Grafiksuchproblem modelliert:

  1. Wir fügen 0als Basisposition ein (Dies wird der Ausgangszustand sein)
  2. Dann sortieren wir die Positionen vom kleinsten zum größten.
  3. Wir machen dann ein BFS / PFS, aus dem das statebesteht
    • Zwei Ganzzahlen lund rdiese repräsentieren einen zusammenhängenden Bereich in dem sortierten Positionsarray, das wir bereits besucht haben
    • Eine Ganzzahl loc, die angibt, ob wir uns am linken oder am rechten Endpunkt des Bereichs befinden
    • Eine Ganzzahl time, die die verstrichene Zeit angibt
    • Eine Ganzzahl 'cost', die die Gesamtkosten angibt (basierend auf den von uns besuchten Knoten)
  4. Aus jedem Zustand können wir zu [l - 1, r] und [l, r + 1] wechseln und die anderen 3 Ganzzahlen entsprechend anpassen
  5. Der Endzustand ist [0, N] und überprüft beide Endpositionen.

Es scheint jedoch, dass [L, R, loc]ein Zustand nicht eindeutig definiert wird, und wir müssen ihn speichern L, R, loc, and time, während wir ihn costbei jedem einzelnen minimieren . Dies führt zu einem exponentiellen Algorithmus, der für alles Gute immer noch viel zu langsam ist.

Kann mir jemand helfen, meine Idee zu erweitern oder in die richtige Richtung zu lenken?

Bearbeiten: Vielleicht kann dies als Problem der Optimierung der dynamischen Programmierung modelliert werden? Wenn man darüber nachdenkt, hat es die gleichen Probleme wie die Graphensuchlösung - nur weil der Strom costniedrig ist, bedeutet dies nicht, dass es die optimale Antwort für dieses Unterproblem ist, da dies timeauch die Antwort stark beeinflusst.

Gierig funktioniert nicht: Ich habe einen Algorithmus für die gierige Auswahl, mit dem die Kosten für den Umzug an einen bestimmten Ort geschätzt werden (z. B. verdoppeln wir die Entfernung zu den linken Fässern und dergleichen, wenn wir uns nach rechts bewegen).

Könnten Sie eine Priority-First-Suche mit einer Heuristik durchführen? Die Heuristik kann die Kosten der aktuellen Reise mit der verstrichenen Zeit kombinieren.

Barron W.
quelle
Wie wäre es mit Shortest Path Algorithmen? Wie der Dijkstra-Algorithmus?
suraj_fale
Ich habe es versucht, aber ich glaube, ich mache etwas wirklich Falsches. Ich habe meinen Algorithmus (Priority First Search oder BFS) unten mit der nummerierten Liste beschrieben.
Barron W.
Dies könnte Ihnen helfen ... stackoverflow.com/q/14639346/585398
suraj_fale
Entschuldigung, ich verstehe nicht, wie diese beiden Probleme zusammenhängen. Können Sie erklären?
Barron W.
2
Dies ist ein ACM-ICPC-Übungsproblem, kein echtes Problem. In einem anderen Punkt habe ich versucht, den Staat zu reduzieren, aber ohne Erfolg. Ich habe versucht, eine DP-Lösung zu schreiben, aber das hat auch nicht funktioniert. Der Staat war L, R, POS.
Barron W.

Antworten:

4

Ich denke, Sie können dies verbessern, indem Sie das Problem als gerichteten Graphen von Positionspaaren betrachten.

In diesem Beispiel verwende ich die Zeile mit den Werten -9, -6, -1, 3 und 5.

Da es zu schwierig ist, eine Grafik nur mit Text zu zeichnen, werde ich die Paare als Tabelle darstellen. Wir können uns die Zellen als den Zustand vorstellen, in dem alle Container zwischen diesen beiden Positionen gesammelt wurden. Jede Zelle hat zwei Werte, von denen einer die Kosten für die Weiterleitung nach links und der andere die Kosten für die Weiterleitung nach rechts (zum nächsten Container) darstellt.

Die Werte können einfach als der Abstand zwischen den beiden Punkten multipliziert mit der Anzahl der Fässer außerhalb dieser beiden Punkte + 1 berechnet werden . Zellen, bei denen beide Nummern dasselbe Vorzeichen haben, stehen für Fälle, in denen alle Fässer mit dem entgegengesetzten Vorzeichen gesammelt wurden. Diese werden nur anhand der Anzahl der Fässer in Richtung von Null berechnet.

In der Tabelle bedeuten die Werte von X, dass Sie nicht in diese Richtung gehen können (alle Fässer in dieser Richtung wurden genommen). Die Zeilen repräsentieren die aktuelle Position des Kollektors und die Spalten repräsentieren die Position des nächsten gegenüberliegenden Zylinders.

    +------+------+------+------+------+
    |  -9  |  -6  |  -1  |   3  |   5  |
+---+------+------+------+------+------+
|-9 |      |      |      | X, 24| X, 14|
+---+------+------+------+------+------+
|-6 | 3, X |      |      | 9, 27| 6, 22|
+---+------+------+------+------+------+
|-1 |      |10, X |      |20, 8 |15, 18|
+---+------+------+------+------+------+
| 3 |24, 4 |27, 6 |16, 8 |      | X, 2 |
+---+------+------+------+------+------+
| 5 |14, X |22, X |18, X |      |      |
+---+------+------+------+------+------+

Die Regeln für das Verschieben zwischen Feldern können etwas verwirrend sein.

Für negativ nummerierte Spalten gelten folgende Regeln:

  • Wenn Sie nach rechts gehen, wird eine Zelle nach unten verschoben.
  • Nach links gehen bewegt sich eine Zelle nach unten und spiegelt sich dann über die Diagonale.
  • Wenn der rechte Wert X ist, wird nach links in die Diagonale verschoben (wo Spalte und Zeile gleich sind) und um eins nach links verschoben.

Für positiv nummerierte Spalten gelten folgende Regeln:

  • Wenn Sie nach links gehen, wird eine Zelle nach oben verschoben.
  • Wenn Sie nach rechts gehen, bewegen Sie sich eine Zelle nach oben und spiegeln dann die Diagonale.
  • Wenn der linke Wert X ist, wird nach rechts in die Diagonale verschoben und um eins nach rechts verschoben.

Jetzt können wir den Algorithmus von Dijkstra ausführen, um den besten Pfad zu berechnen, wobei wir diese Bewegungsregeln verwenden, um den Graphen zu durchlaufen. Unsere Startpositionen sind (-1, 3) und (3, -1) mit anfänglichen Kosten von 5 bzw. 15. Sobald wir die Werte für die beiden Endpositionen (links von (-9, -9) und rechts von (5, 5)) berechnet haben, ist die kleinere der beiden unsere Antwort.

Die Laufzeit für jeden der Schritte beträgt:

  • O (N log N) zum anfänglichen Sortieren der Eingabewerte entlang der Linie
  • O (N ^ 2) zur Berechnung der Tabelle / Grafik
  • O (N ^ 2 log N) zum Ausführen von Dijkstra's in der Grafik (Hinweis: Es gibt höchstens zwei Kanten für einen bestimmten Scheitelpunkt).

Die ersten beiden Schritte werden vom letzten dominiert, daher ist Ihre Gesamtlaufzeit O (N ^ 2 log N), was für die Herausforderung eine ausreichend gute Laufzeit sein sollte.

Cameron
quelle
1

Kürzeste Entfernung

Ich habe gestern eine Java-Anwendung geschrieben, um das Problem zu lösen. Das Problem ist im Grunde ein Problem der kürzesten Entfernung, wie SRJ in seinem Kommentar sagte. Die Strahlung zeigt nur, dass Sie einen Wert zusammen mit der kürzesten Entfernung akkumulieren können.

Grundsätzlich ist hier was ich getan habe.

  • Fügen Sie die Containernummern in eine Liste <Integer> ein
  • Während die Liste Elemente enthält;
    • Suchen Sie die Elemente, die am nächsten sind
    • Wenn es ein Element gibt, gehen Sie dorthin und entfernen Sie das Element.
    • Wenn zwei Elemente vorhanden sind, kopieren Sie den Pfad und gehen Sie zu beiden Elementen
  • Finden Sie den Weg mit dem kleinsten Strahlungswert.

Hier sind einige Ausgaben aus der Anwendung

10 containers are located at [-90, -75, -47, -9, 9, 26, 48, 50, 64, 79].

You walk to position -9 and pick up the container.  The total radiation emitted is 90 units.
You walk to position 9 and pick up the container.  The total radiation emitted is 252 units.
You walk to position 26 and pick up the container.  The total radiation emitted is 388 units.
You walk to position 48 and pick up the container.  The total radiation emitted is 542 units.
You walk to position 50 and pick up the container.  The total radiation emitted is 554 units.
You walk to position 64 and pick up the container.  The total radiation emitted is 624 units.
You walk to position 79 and pick up the container.  The total radiation emitted is 684 units.
You walk to position -47 and pick up the container.  The total radiation emitted is 1,062 units.
You walk to position -75 and pick up the container.  The total radiation emitted is 1,118 units.
You walk to position -90 and pick up the container.  The total radiation emitted is 1,133 units.

Ich habe den Algorithmus in keiner Weise optimiert. Ich habe nicht einmal bemerkt, dass die Liste der eingegebenen Zahlen sortiert war. (Ich bin ein doofus.)

Als ich meinen Code mit den Maximalwerten, 1.000 Containern und einem Bereich von -500.000 bis 500.000 ausführte, dauerte die Ausführung meines Codes 3 Sekunden. Die meiste Zeit wurden die 1.000 Druckzeilen auf die Konsole geschrieben.

Ich bin keine große O-Person, aber ich denke, dass meine rohe Kraft, die den kürzesten Weg geht, O (N im Quadrat) ist, nicht O (N!).

Wenn ich die Tatsache ausnutzen würde, dass die eingegebenen Zahlen sortiert sind, so dass ich nur die beiden Zahlen auf beiden Seiten meines derzeitigen Standorts überprüfen müsste, könnte ich die Bewerbung in die Nähe von O (N) bringen. Ich muss nur 2 Zahlen überprüfen, da ich die Elemente von der Liste entferne, wenn ich zu ihnen komme.

Sie haben verschiedene Algorithmen wie den Greedy-Algorithmus verwendet, um eine ungefähre Lösung zu finden.

Wenn die Ausführung meines Programms 3 Stunden statt 3 Sekunden gedauert hätte, hätten Sie die Wahl.

Ist die Lösung gut genug gut genug?

Mit anderen Worten, bin ich bereit, die Verarbeitungsgeschwindigkeit gegen eine ausreichend gute Antwort einzutauschen?

Wenn eine ausreichend gute Antwort ausreichend ist, verwenden Sie Approximationsalgorithmen.

Wenn Sie die perfekte Antwort wollen, müssen Sie die kürzesten Wege gehen. Es gibt keine Abkürzung.

Wenn jemand möchte, dass ich meinen Code poste, werde ich das tun. Ich bin mir sicher, dass es immer noch Fehler gibt, da ich sehen wollte, ob ich einen Algorithmus für kürzestes Gehen implementieren kann.

Gilbert Le Blanc
quelle
1

Ich habe eine Lösung, die dieses Problem mit der 2^NZeit lösen kann , aber ich denke, sie ist eine hilfreiche Methode, um das Problem einzugrenzen. Deshalb dachte ich, ich würde posten.

Anstatt das Problem als Diagramm zu modellieren, würde ich modellieren, dass es ein binärer Entscheidungsbaum ist (sagen wir T). In jedem Level musst du zwischen rechts und links wählen. Es ist ziemlich einfach, die "Kosten" jeder Kante zu berechnen. Sei h(K)die Höhe des aktuellen Knotens, Kdann die Kosten für die Kante, zu der es geht left_child(K) = h(K) x dist(K, left_child(K)). Eine ähnliche Berechnung reicht für die Kosten der Kante zum richtigen Kind aus. Sie erstellen diesen Baum, verfolgen die kumulativen Kosten der Kanten bis zum Ende und geben den Pfad zum Blattknoten mit den geringsten Gesamtkosten an.

Beachten Sie, dass die Kostenberechnung funktioniert, da die Länge jeder Kante dist(K, left_child(K))die Zeit darstellt, um zur nächsten Stelle zu gelangen, während die Höhe des Unterbaums die Anzahl der verbleibenden Stellen ist (z. B. noch Strahlung emittierend).

Der Trick in diesem Framework besteht nun darin, festzustellen, ob es einige Heuristiken gibt, mit denen Sie "beweisen" können, dass Sie die Erweiterung der Suche entlang eines Zweigs ignorieren können. Meine Intuition ist, dass es für jede solche Heuristik eine Anordnung von Sites gibt, die sie besiegen, aber vielleicht kann sich jemand etwas einfallen lassen.

Einige haben vorgeschlagen, Lösungen mit kürzesten Wegen für Graphen anzuwenden. Ich habe einige Zweifel, ob eine solche Lösung funktionieren kann. Ihre Nachbarn in der Grafik des Problems ändern sich je nach dem Pfad, dem Sie folgen. Zum Beispiel in Ihrem ursprünglichen Beitrag mit, [-12, -2, 3, 7]wenn Sie zu -2dann gehen -12und 3"Nachbarn" werden, und wenn Sie zu 3dann gehen -2und 7Nachbarn sind. Jedes mögliche "Paar" positiver und negativer Werte kann im endgültigen Diagramm möglicherweise Nachbarn sein. Ich kenne keine Algorithmen für kürzeste Wege, die in einem dynamischen Graphen nachweislich korrekt sind.

Craig Dillabaugh
quelle
0

Ich denke, es ist am sinnvollsten, sich jede Etappe einfach als eine binäre Wahl zwischen rechts zum nächsten Fass und links zum nächsten Fass vorzustellen. Haben Sie einfach eine Kostenfunktion, die die Anzahl der Strahlungseinheiten angibt, die insgesamt durch eine Bewegung entstehen würden, und wählen Sie diejenige mit den niedrigsten Kosten aus.

Betrachten Sie NICHT einfach das nächstgelegene Fass, sondern gehen Sie davon aus, dass Sie durch die Entfernung von einem Fass effektiv die doppelte Strahlung hinzufügen, da Sie durch die Entfernung auch die Kosten für das spätere Zurückbewegen in diese Richtung verursacht haben.

In Ihrem Beispiel von [-12, -2,3,7] würde eine Bewegung nach links insgesamt 14 (2 + 2 + 10) links und 18 (2 + 2 + 5 + 9) rechts verursachen. Wenn Sie sich nach rechts bewegen, werden 10 (3 + 3 + 4) rechts und 26 (3 + 3 + 5 + 15) rechts angezeigt. Klar links ist zunächst die richtige Lösung. Eine ähnliche Berechnung kann für jede aufeinanderfolgende Bewegung durchgeführt werden.

Danach reduziert sich das Problem im Wesentlichen auf eine Suche, daher sollte die Komplexität O (nlog (n)) sein, was VIEL besser ist als O (n!). Ich glaube, dass dies notwendigerweise die niedrigste Komplexität ist, die für dieses Problem existieren kann, da es sich im Grunde um einen vergleichsbasierten Suchalgorithmus handelt, für den es nicht möglich ist, eine bessere Leistung als O (nlog (n)) zu erzielen.

Anscheinend war mir diese Beschreibung nicht klar genug, und deshalb habe ich beschlossen, sie etwas programmatischer zu gestalten: 1. Berechnen Sie die Kosten für Links- und Rechtslauf anhand der aktuellen Position. 2. Ziehen Sie ein die günstigste Richtung 3. Entfernen Sie das erreichte Fass aus der Betrachtung bei der Berechnung der Kosten für das Bewegen in eine Richtung

Berechnung der Kosten: 1. Identifizieren Sie das nächstgelegene Fass in der angegebenen Richtung. Angenommen, $ dist ist die Entfernung von der aktuellen Position zum nächsten Fass in der angegebenen Richtung. 2. Die Kosten werden als N * $ dist initialisiert, wobei N nur noch aktive Fässer berücksichtigt. 3. Addieren Sie dazu den Abstand, den die durch $ dist angegebene neue Position von jedem verbleibenden Fass haben würde.

Slater Victoroff
quelle
1
Das funktioniert nicht immer. Vielleicht können Sie die Koordinaten sortieren und dann eine Suche durchführen, bei der der Bundesstaat einen Bereich [i..j] (der angibt, welchen Bereich Sie besucht haben) sowie die Kosten und die aktuelle Zeit enthält.
Barron W.
Wann funktioniert das nicht?
Slater Victoroff
Es gab einen einfachen Testfall, bei dem dies fehlschlug. Ich werde versuchen, es zu finden, aber es war mit N = 4 oder 5.
Barron W.
[43, -18, -98, -82, 63]
Barron W.
Auch Fälle mögen [-10,-11, 10,20,30,40,50,60,70]. Die richtige und einzige Lösung besteht darin, alle negativen und dann die positiven zu sammeln. Für eine Antwort von 455.
Barron W.
0

Teillösung - Ich werde später darauf zurückkommen.

Angenommen, die "Standard" -Strategie wird ganz nach links oder rechts ausgeführt, je nachdem, was billiger ist. Fragen Sie jetzt, ob es einen kleinen Abstecher wert ist, ein Fass in die andere Richtung zu holen. Es ist ziemlich einfach, die Antwort zu berechnen.

Für Sie ist es billiger, wenn Sie den gesamten Weg nach rechts laufen lassen, als wenn Sie den gesamten Weg nach links laufen lassen. Lohnt sich ein Abstecher nach -2? Es reduziert die Kosten für das Laufen ganz nach rechts und dann wieder auf 0 um 14 (weil Sie bei der Standardstrategie 4 Strahlungseinheiten pro Zug von 0 auf 3 "gezahlt" haben, jetzt sind es nur noch 3, Sie haben 3 von 3 gezahlt) bis 7, jetzt sind es 2, usw.), plus um eins pro Zug reduzieren sich Ihre Kosten für den Umzug von 0 auf -2, wodurch 2 weitere für insgesamt 16 gespart werden.

Es addiert jedoch die Kosten für den Wechsel von -2 zu 0 von 14 (4 Einheiten pro Zug zu -2, 3 Einheiten pro Zug zurück zu 0) für einen Nettogewinn von (16-14) = 2. Um dies zu berechnen, müssen Sie nicht die genauen Kosten für die Lösung des gesamten Problems für jede Entscheidung abschätzen. Sie verfügen über genügend Informationen, um zu entscheiden, ob das Laufen ganz nach links billiger ist als das Laufen ganz nach rechts und wie Viele Abfallbehälter befinden sich auf jeder Seite von Ihnen und der Abstand zur nächsten 2. Das ist also O (N ^ 2).

Abgesehen von einem wichtigen Problem - ich bin davon ausgegangen, dass Sie bis zum Ende durchstarten werden, und wir wissen, dass Sie sich möglicherweise verdoppeln werden. Um das zu bereinigen, müssen wir meine Berechnung aktualisieren. Bei der Probeneingabe habe ich angenommen, dass Sie 14 einsparen würden, indem Sie 1 weniger Gesamtstrahlung pro Einheit pro Sekunde emittieren, während Sie von 0 auf 7 und zurück laufen. Wenn Sie jedoch vor dem Laufen auf 7 zurückdrehen, werden die Einsparungen reduziert.

Das ist ziemlich schlimm, weil ich nicht weiß, wie ich das nächste Double-Back berechnen soll, ohne alle Möglichkeiten auszuprobieren, was uns zu O (2 ^ N) zurückführt.

Außer - es ist 2 ^ N mit dem Beschneiden. Ich habe berechnet, dass der "Abstecher" zu -2 14 gekostet hat, aber 16 gewonnen hat, wenn ich nicht mehr Abstecher hatte, bevor ich es bis zur ganz rechten Zahl geschafft habe. Wenn die am weitesten rechts stehende Zahl 5 gewesen wäre, würde ich sofort wissen, dass sich der Abstecher zu -2 nicht auszahlen könnte. (Kosten immer noch 14, maximaler Nutzen 12). Ich muss auch nicht in Betracht ziehen, zu -2 zu gehen und dann vor Erreichen von 6 einen Abstecher zu machen, da dies immer schlechter ist, als erst direkt zu diesem Punkt zu gelangen.

bA
quelle
0

Ich denke, Sie können es mit einer Breitensuche lösen, indem Sie nicht mehr als 2 * N ^ 2 Tupel (boolean, int, int, int, string) beibehalten, wobei die Zeichenfolgen so lang sind, wie der Pfad kompliziert ist.

Die Tupel sind (min oder max boolesch, min zurückgelegte Position, max zurückgelegte Position, emittierte Gesamtstrahlung, Pfadverlauf).

Ich sehe den Algorithmus so:

  1. Initialisieren Sie den Tupelpool mit einem einzelnen Eintrag (min, 0, 0, 0, "").
  2. Suchen Sie ein Element im Pool, das nur eine minimale Strahlungsemission aufweist. Wenn min und max den min und max aller Fässer entsprechen, ist die Pfadhistorie die optimale Lösung. Andernfalls löschen Sie es aus dem Pool.
  3. Berechnen Sie die 2 Nachkommen dieses Tupels, von denen jedes dem Gehen nach links oder rechts zum nächsten unbearbeiteten Fass entspricht.
  4. Fügen Sie die Nachkommen in den Pool ein. Befindet sich bereits ein Element im Pool mit demselben Booleschen Wert (Boolean), Min. Und Max. Als neuer Nachkomme, verwerfen Sie das Element mit der höheren Strahlungszahl.
  5. gehe zu 2

Das Suchen und Entfernen dominierter Tupel verbessert die Leistung erheblich. Es kann sich lohnen, jedem Tupel ein Flag "Hat gezüchtet" hinzuzufügen und gezüchtete Tupel im Pool zu belassen.

Es müssen auch einige wichtige Entscheidungen getroffen werden, um zu entscheiden, wie die Tupel gespeichert werden sollen, und um sie nach Herrschaften und neuen Elementen zu durchsuchen, die gezüchtet werden sollen.

NovaDenizen
quelle