Während ich über ein Problem nachdachte, wurde mir klar, dass ich einen effizienten Algorithmus erstellen muss, der die folgende Aufgabe löst:
Das Problem: Wir erhalten einen zweidimensionalen quadratischen Kasten der Seite dessen Seiten parallel zu den Achsen sind. Wir können es von oben untersuchen. Es gibt jedoch auch horizontale Segmente. Jedes Segment hat eine ganzzahlige Koordinate ( ) und Koordinaten ( ) und verbindet die Punkte und (siehe Bild unten).m y 0 ≤ y ≤ n x 0 ≤ x 1 < x 2 ≤ n ( x 1 , y ) ( x 2 , y )
Wir möchten für jedes Einheitensegment oben auf der Box wissen, wie tief wir vertikal in die Box schauen können, wenn wir durch dieses Segment schauen.
Formal möchten wir für .
Beispiel: Bei und Segmenten, die sich wie im Bild unten befinden, ist das Ergebnis . Schauen Sie sich an, wie tiefes Licht in die Box gelangen kann.
Zum Glück für uns beide und sind recht klein und wir können die Berechnungen off-line tun.
Der einfachste Algorithmus zur Lösung dieses Problems ist Brute-Force: Durchlaufen Sie für jedes Segment das gesamte Array und aktualisieren Sie es bei Bedarf. Es gibt uns jedoch nicht sehr beeindruckend .
Eine große Verbesserung besteht darin, einen Segmentbaum zu verwenden, der in der Lage ist, Werte auf dem Segment während der Abfrage zu maximieren und die Endwerte zu lesen. Ich werde es nicht weiter beschreiben, aber wir sehen, dass die Zeitkomplexität .
Ich habe mir jedoch einen schnelleren Algorithmus ausgedacht:
Gliederung:
Sortieren Sie die Segmente in absteigender Reihenfolge der Koordinate (lineare Zeit unter Verwendung einer Variation der Zählsortierung). Es ist nun zu beachten, dass, wenn ein Einheits-Segment zuvor von einem Segment abgedeckt wurde, kein nachfolgendes Segment den Lichtstrahl mehr durch dieses Einheits-Segment binden kann. Dann fegen wir eine Linie von oben nach unten.
Nun führen sie einige Definitionen: -Einheit Segment ist ein imaginäres horizontales Segment auf der Schleife , deren - Koordinaten ganze Zahlen sind und deren Länge ist 1. Jedes Segment während des Durchlaufprozesses kann entweder unmarkiert (das heißt, ein Lichtstrahl geht aus dem Der obere Rand der Box kann dieses Segment erreichen) oder markiert sein (gegenüberliegender Fall). Stellen Sie sich ein Einheitensegment vor, bei dem , immer unmarkiert ist. wir uns auch die Mengen . Jeder Satz enthält eine ganze Sequenz von aufeinanderfolgenden markierten Einheitensegmenten (falls vorhanden) mit folgenden nicht markierten Segment.
Wir brauchen eine Datenstruktur, die in der Lage ist, diese Segmente und Mengen effizient zu bearbeiten. Wir werden eine Find-Union-Struktur verwenden, die um ein Feld erweitert ist, das den maximalen unit-Segmentindex (Index des nicht markierten Segments) enthält.
Jetzt können wir die Segmente effizient handhaben. Nehmen wir an, wir betrachten jetzt das te Segment in der Reihenfolge (nennen es "Abfrage"), das in beginnt und in endet . Wir müssen alle nicht markierten Einheitssegmente finden, die innerhalb des ten Segments enthalten sind (dies sind genau die Segmente, auf denen der Lichtstrahl seinen Weg beenden wird). Wir werden Folgendes tun: Erstens finden wir das erste nicht markierte Segment in der Abfrage ( Finden Sie den Repräsentanten der Menge, in der enthalten ist, und erhalten Sie den maximalen Index dieser Menge, die per Definition das nicht markierte Segment ist ). Dann wird dieser Index Wenn Sie sich in der Abfrage befinden, fügen Sie sie zum Ergebnis hinzu (das Ergebnis für dieses Segment ist ) und markieren Sie diesen Index ( Union- Mengen mit und ). Dann wiederholen Sie diesen Vorgang , bis wir alle finden nicht markierten Segmente, das heißt, neben Suche Abfrage gibt uns Index .
Beachten Sie, dass jede Find-Union-Operation nur in zwei Fällen ausgeführt wird: Entweder beginnen wir mit der Betrachtung eines Segments (was mal vorkommen kann), oder wir haben gerade ein unit-Segment markiert (dies kann mal vorkommen). Die Gesamtkomplexität ist also ( ist eine inverse Ackermann-Funktion ). Wenn etwas nicht klar ist, kann ich darauf näher eingehen. Vielleicht kann ich ein paar Bilder hinzufügen, wenn ich Zeit habe.
Jetzt erreichte ich "die Mauer". Ich kann mir keinen linearen Algorithmus ausdenken, obwohl es einen geben sollte. Ich habe also zwei Fragen:
- Gibt es einen linearen Zeitalgorithmus (d. H. ), der das Sichtbarkeitsproblem für horizontale Segmente löst?
- Wenn nicht, was ist der Beweis, dass das Sichtbarkeitsproblem ?