Rheinische Friedrich-Wilhelms-Universität Bonn Institut für Informatik I Andri Bremm Effektives Platzieren von Wächtern in Galerien 5. Januar 2009 Seminararbeit im Sommersemester 2008 Zusammenfassung Die Seminararbeit beschäftigt sich damit, wie man effektiv eine minimale Anzahl von Wächtern in einem Polygon platziert, so dass dieses komplett überwacht ist. Dazu werden zwei Ansätze betrachtet. Im ersten Ansatz sind die Positionen der Wächte auf die Eckpunkte des Polygons beschränkt und im zweiten Ansatz werden die Wächter beliebig auf einem engen Raster innerhalb des Polygons plaziert. Außerdem wird die Erweiterung des Algorithmusses auf Polygone mit Löchern und auf Gelände dargestellt. Inhaltsverzeichnis 1 Einführung 2 2 Grundlegende Definitionen 2 3 Platzierung der Wächter auf den Eckpunkten 2 4 Exakter Algorithmus für eine feste Anzahl von Wächtern 4 5 Platzierung der Wächter auf einem 5.1 Bereichsanfrage auf einem Raster . 5.2 Erweiterter Suchbaum . . . . . . . 5.3 Verwendung der Datenstruktur . . 5.4 Der Algorithmus . . . . . . . . . . Raster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 7 8 11 14 6 Polygone mit Löchern 17 6.1 Sichtbarkeit in Polygonen mit Löchern . . . . . . . . . . . . . 17 1 1 Einführung Als das Kunstgalerie-Problem bezeichnent man die Frage, wie groß die minimale Anzahl von Wächtern ist, die benötigt werden, um ein Museum zu bewachen. Das Museum wird dabei durch ein einfaches Polygon P mit n Ecken repräsentiert und die Wächter sind Punkte innerhalb des Polygons. Wir sagen das sich zwei Punkte aus P sehen, wenn eine Gerade zwischen den beiden Punkten auch in P liegt. Die Bestimmung der minimalen Anzahl von Wächtern ist NP-hart [5]. Um ein effektives platzieren der Wächter zu ermöglichen, beschäftigen wir uns mit Algorithmen, die mit einer hohen Wahrscheinlichkeit eine Lösung liefern. Sie wurden 2006 von Alon Efrat und Sariel Har-Peled [3] vorgestellt. 2 Grundlegende Definitionen Definition 1 Sei P ein einfaches Polygon. Für ein Punkt q ∈ P bezeichnet Vis(q) das Sichtbarkeitspolygon von q in P. Vis(q) sind alle Punkte von P, die von q aus gesehen werden bzw. alle Punke von P die q sehen. Sein G = {g1 ...gk } eine Menge von k Punkten in P. Dann bezeichnet V is(G) = V is(g1 ) ∪ V is(g2 ) ∪ ... ∪ V is(gk ) die Vereinigung der Sichtbarkeitspolygone von g1 ...gk . Theorem 2 Das Sichtbarkeitspolygon Vis(G) ist durch O(nk + k 2 ) Kannten begrenzt. Diese Schranke ist eng im worstcase. Vis(G) lässt sich effizient mit einem divide and conquer Algorithmus berechnen. Für einen Punkt q ∈ P lässt sich Vis(q) in O(n) Zeit berechnen. Wenn wir mehr als einen Punkt haben, teilen wir die Menge G in zwei Hälften mit je ca. k/2 vielen Punkten. Nachdem für beide Teilmengen das Sichtbarkeitspolygon berechnet wurde, fügen wir sie mit einem SweepVerfahren zusammen. Die Laufzeit ergibt sich aus der benötigten Zeit für das Berechnen der Sichtbarkeitspolygone der einelementigen Teilmengen und der Zeit für das Zusammenfügen der Polygone. Insgesammt kommen wir so auf eine Laufzeit von O((nk + k 2 )log k log n). 3 Platzierung der Wächter auf den Eckpunkten Der im folgenden beschriebene Algorithmus findet mit hoher Warscheinlichkeit eine möglichst kleine Teilmenge der Eckpunkte des Polygons, so dass, 2 wenn wir auf diesen Punkten die Wächter platzieren, diese das ganze Polygon überwachen können. Sei V die Menge der n Eckpunkte eines einfachen Polygons P . Alle Eckpunkte, die von einem Punkt q ∈ P gesehen werden bezeichnen wir mit Vq . Vq = V ∩ V is(q) Die Menge aller Teilmengen von V , die von einem Punkt q ∈ P gesehen werden bezeichnen wir mit V. V = {Vq | q ∈ P } Da wir wissen, dass die VC-dimension des Mengensystems Y = (P, {V is(q)|q ∈ P } beschränkt ist, muss auch die VC-dimension unseres kleineren Mengensystems X = (V, V) beschränkt sein. Eine Menge von Wächtern auf den Eckpunkten von P zu finden, die ganz P sehen, ist äquivalent dazu eine Menge U ⊆ V zu finden, die aus mindestens einem Repräsentanten jede Menge aus V besteht. Also dass ∀X ∈ V gilt, dass X ∩ U 6= ∅. Algorithmus 3.1 bestimmt mit hoher Wahrscheinlichkeit eine Menge von Wächtern, die P ganz überwachen. Er ist auf Seite 5 abgebildet. Der Algorithmus versucht anstelle einer optimalen Lösung O(k log k) viele Wächter zu finden. Die Wächter dürfen nur auf den Eckpunkten des Polygons platziert werden und es gilt: k ≥ copt . Dabei ist copt die kleinstmögliche Anzahl von Wächtern, mit der P ganz eingesehen werden kann. Wenn copt nicht bekannt ist, wird k mit 1 initialisiert. Andernfalls kann k auf copt gesetzt werden. Dann wird die Funktion ComputeGuards(P, k) aufgerufen. Die Funktion ComputeGuards(P, k) berechnet mit hoher Wahrscheinlichkeit eine Menge von O(k log k) vielen Wächtern, die P überwachen, falls k ≥ copt ist. Dazu speichert ComputeGuards(P, k) zu jedem Eckpunkt von P ein Gewicht. Zu Beginn hat jeder Punkt ein Gewicht von 1. Dann wird O(k log nk ) mal versucht eine geeignete Menge an Wächtern zu finden. Dazu wählt man zufällig, aber abhäning von ihren Gewichten, O(k log k) Eckpunkte von P aus. Für die gewählten Wächter prüft man ob sie ganz P einsehen können. Wenn ja berichtet man die gefundene Menge, ansonsten sucht man ein Punkt q in P der nicht gesehen wird. Dann verdoppelt man das Gewicht von jedem Punkt den q sieht, wenn das k fache der Summe all dieser Gewicht kleiner oder gleich der Hälfte der Gesamtsumme aller Gewichte ist. Nachdem die Gewichte aktualisiert wurden, versucht man erneut eine geeignete Menge zu finden, unabhängig von den zuvor gewähten Wächtern. Wird bei allen Versuchen keine geeignete Menge gefunden, wird die leere Menge zurückgegeben. Wenn die Funktion ComputeGuards(P, k) keine Menge von Wächtern gefunden hat, ist k wahrscheinlich zu klein gewesen. Daher wird k verdoppelt 3 und die Funktion ComputeGuards(P, k)) erneut aufgerufen. Das wird so oft wiederholt, bis eine Menge von Wächtern gefunden wurde. Was für eine Laufzeit hat der Algorithmus? Die Funktion ComputeGuards(P, k) wird O(logcopt ) mal aufgerufen. Das ergibt sich daraus, dass k nach jedem Aufruf verdoppelt wird solange bis k ≥ copt ist. Die Funktion ComputeGuards(P, k) macht O(k log( nk ) Iterationen. Eine Iteration hat einen Aufwand von O(nk log n log k), für den hauptsächlich das Prüfen, ob die Wächter der gewählten Menge ganz P sehen, verantwortlich ist. Damit kommt man für einen Aufruf von ComputeGuards(P, k) auf Kosten von insgesamt O(k log ( nk ) ∗ O(nk log n log k) = O(nk 2 log n log nk log k). Diese Kosten summieren wir über die O(log copt ) Aufrufe auf. O P log copt i=1 n(2i )2 log n log O nc2opt log n log n copt n (2i ) log (2i ) = log copt Theorem 3 Für ein einfaches Polygon P mit n Eckpunkten kann man in n O(nc2opt log n log copt log copt ) erwarteter Zeit, eine Menge S von O(copt log copt ) vielen Wächtern, auf den Eckpunkten von P, berechnen. Dabei ist copt die Kardinalität der kleinsten Menge an Wächtern, die ganz P sehen. 4 Exakter Algorithmus für eine feste Anzahl von Wächtern Theorem 4 Man kann die kleinste Menge von Wächtern, die ein gegebenes eifaches Polygon mit n Ecken komplett einsenen können in O((nk)3(2k+1) ) Zeit berechnen, wobei k die Kardinalität einer solchen optimalen Menge ist. Beweis. Die ist eine einfache Konsequenz aus bekannten Techniken der reell-algebraische Geometrie. Angenommen, wir wollen zunächst nur feststellen ob es eine Menge von k Wächtern gibt, die P ganz sehen. Das ist äquivalent dazu, für folgender prädikatenlogischer Aussage zu entscheiden, ob sie wahr ist. ∃ x1 , y1 , x2 , y2 , ..., xk , yk ∀ u, v | [InP (u, v) ⇒ (V isib(x1 , y1 ; u, v) ∨ V isib(x2 , y2 ; u, v) ∨ ... ∨ V isib(xk , yk ; u, v))] Das Prädikat InP (u, v) ist wahr, wenn (u, v) ∈ P . V isib(x, y; u, v) ist wahr, wenn (x, y), (u, v) ∈ P und sie sich gegenseitig sehen können. Die prädikatenlogische Aussage formuliert, dass es k Punkte gibt und für jeden beliebigen Punkt gilt, wenn er in dem Polygon liegt, so wird er von mindestens einem der k Punkte gesehen. 4 Algorithmus 3.1 Bestimmung der Wächter // P ist das einfache Polygon für das die Wächter bestimmt werden. // V ist die Menge der Eckpunkte von P . // Falls copt unbekannt ist, wird k mit 1 initialisiert. k := 1; repeat S := ComputeGuards(P, k) if S 6= ∅ then Berichtet die Wächter S else // k ist wahrscheinlich zu klein k := k + k end if until Eine Menge von Wächtern gefunden wurde. ComputeGuards(P, k){ Jedem Punkt aus V wird ein Gewicht von 1 zugeordnet. for i = 1 to O(k log( nk )) do bestimme eine Menge S ⊆ V , indem man O(k logk) Punkte zufällig und unabhänging wählt, aber entsprechend ihren Gewichten if Die Punkte von S sehen ganz P then return S else suche einen Punkt q ∈ P der nicht von S sichtbar ist berechne Vis(q) W := Summe der Gewichte aus V ∩ V is(q) if 2kW ≤ Summe aller Gewichte in V then verdopple die Gewichte aller Punkte aus V ∩ V is(q) end if end if end for return ∅ } 5 InP (u, v) ist eine Boolean combination“ aus O(n) linearen Ungleichheiten. ” V isib(x, y; u, v) ist eine Boolean combination“ aus O(n) quadratischen Un” gleichheiten. Daher schließn alle Prädkate nur O(nk) Polygone des 2. Grades ein und haben nur ein Wechsel der Quantoren. Durch das Ergebnis von Basu, Pollack und Roy [1], ist die Entscheidung, ob die Aussage wahr ist, in O((nk)3(2k+1) ) Zeit möglich. Das Optimum für k zu finden, ist durch eine lineare Suche in asymtotisch der gleichen Zeit möglich. 2 5 Platzierung der Wächter auf einem Raster In diesem Kapitel erweitern wir Algorithmus 3.1, bei dem die Position der Wächter auf die Eckpunkte des Polygons beschränkt waren. Unser Ziel ist es, eine möglichst gute Lösung für das Kunstgalerie-Problem zu finden. Dazu werden wir ein enges Raster definieren und über das Polygon legen. Die Einschränkung der Positionierung der Wächter erweitern wir von den Eckpunkten auf alle Raterpunkte innerhalb des Polygons. Intuitiv ist eine solche, möglichst klein gehaltene Menge, auch eine gute approximation für die Kardinalität einer optimalen Menge von Wächtern, die beliebig in den Polygon platziert wurde. Der Algorithmus in diesem Kapitel unterscheidet sich vom Algorithmus 3.1 nur in der Art, wie die Gewichte für die einzelnen Rasterpunkte gespeichert und gepflegt werden und der Methode, die die Menge der Wächter bestimmt. Der grobe Ablauf des Algorithmus bleibt gleich. Gegeben ist ein einfaches Polygon P , mit einer Menge V von n Eckpunkten und einem Durchmesser d ≤ 1. Wir definieren ein Raster Γ mit einem Punkteabstand von > 0 in Axenrichtung, dessen Punkte alle innerhalb von P liegen. Γ = P ∩ {(i, j)|i, j ∈ ZZ)} Der Algorithmus findet eine Menge von O(copt log copt ) vielen Wächtern G ⊆ Γ, wobei copt die Kardinalität der kleinsten Menge von Punkten aus Γ ist, die ganz P sehen. Insgesamt benötigt Algorithmus 5.1 eine Laufzeit von O nc2opt log copt log(ncopt ) log 2 ∆ wobei ∆ = d ist. Die Hauptidee von diesem Algorithmus ist es, das Pflegen der Gewichte nicht mehr einzeln, wie bei Algorithmus 3.1 zu machen. Statt dessen werden wir die Eigenschaften der Gewichteverteilung nutzen, um die Gewichte gebietweise zu pflegen. Wenn wir uns errinnern, wurden immer alle Gewichte der Punkte verdoppelt, die im Sichtbarkeitspolygon eines nicht gesehenen Punktes liegen. Im Verlauf des Algorithmus tauchen viele dieser Sichtbarkeitspolygone auf. Wenn wir uns eine Zusammenstellung aus allen 6 Sichtbarkeitspolygonen und dem Polygon P vorstellen, ist klar, dass alle Punkte in einer Zelle dieser Zusammenstellung das gleiche Gewicht haben. Denn zu Beginn waren die Gewichte aller Punkte gleich und sie wurden nur pro Sichtbarkeitspolygon verändert. Für eine Menge M = {p1 , ..., pk } von k Punkten bezeichnet A die Zusammenstellung von k Sichtbarkeitspolygonen. A = A(M ) = ∂V is(p1 ) ∪ ... ∪ ∂V is(qk ) Die Komplexität einer solchen Zusammenstellung A ist in O(nk 2 ). Die Zone von ∂V is(q) in A bezeichnet alle Punkte von allen Kanten aus A, die zu einer Zelle gehören, die durch das Einfügen von V is(q) geschnitten wird. Die Komplexität einer Zone von ∂V is(q) in A ist in O(nkα(k)), wobei α(n) die inverse Ackermann-Funktion ist. Die inverse Ackermann-Funktion ist eine extrem langsam wachsende Funktion. Bevor wir uns in Abschnitt 5.2 auf Seite 8 eine geeignete Datenstruktur anschauen, die eine solche Zusammenstellung speichern kann und alle von uns benötigten Funktionen unterstützt, betrachten wir noch zwei Erkenntnisse im Umgang mit einem Raster. 5.1 Bereichsanfrage auf einem Raster Wenn wir eine Zusammenstellung gespeichert haben und ihr ein weiteres Sichtbarkeitspolygon hinzufügen wollen, müssen wir die Anzahl der Raterpunkte in den beiden verbleibenden Teilen der Zelle bestimmen. 7 Lemma 5 Sei T ein Dreieck und Γ ein Raster in T. Dann kann man die konvexe Hülle CH(Γ∩T) und die Anzahl der Rasterpunkte innerhalb von T mit einer Laufzeit von O(log∆) bestimmen. Dabei ist ∆ der Quotient des Durchmessers von T und der Rastergröße. Beweis. Nach S. Kahan und J. Snoeyink [4] kann man, die Konvexe Hülle eines Rasters, unter einer Linie der Länge M, in O(log M ) berechen. Wir wenden das auf die drei Seiten von T an und erhalten so CH(Γ∩T) in O(log ∆). Mit Pick’s Theorem [7] bekommen wir die Anzahl der Punkte in CH(Γ∩T). 2 Bei unserem Algorithmus müssen wir die Wächter zufällig wählen. Angenommen wir haben uns bereits für eine Zelle entschieden, dann müssen wir aus dieser Zelle zufällig einen Rasterpunkt auswählen, wobei jeder Rasterpunkt die gleiche Wahrscheinlichkeit haben soll, ausgewählt zu werden. Lemma 6 Seien T, Γ und ∆ wie in Lemma 5. Dann kann man zufällig einen Punkt aus T ∩ Γ auswählen, wobei jeder Rasterpunkt mit der gleichen Wahrscheinlichkeit gezogen wird. Die Laufzeit dazu liegt in O(log 2 ∆). Beweis. Die Idee ist es, das Dreieck T solange vertikal zu teilen, bis wir nur noch eine Reihe von Rasterpunkten übrighaben. Dazu legen wir eine Bounding-Box B0 um das Dreieck T. In der i-ten Iteration haben wir die Bounding-Box Bi−1 und teilen diese vertikal mit einer Linie li in eine linke und eine rechte Hälfe BiL und BiR , so dass li auf keinem Rasterpunkt liegt. Nach Lemma 5 können wir die Anzahl der Punke in einer Hälfte in O(log∆) Zeit berechnen. Sei wi die Anzahl der Rasterpunkte in der linken Hälfte. w0 bezeichnet die Anzahl der Rasterpunkte in T. Damit alle Punkte mit gleicher Wahrscheinlichkeit gewählt werden, entscheiden wir uns mit einer i Wahrscheinlichkeit von p = wwi−1 für die linke Seite und mit einer Wahrscheinlichkeit q = 1 − p für die rechte Seite. Falls wir uns für die rechte Seite entscheiden setzen wir wi = wi−1 −wi . Wir führen dies solange durch, bis nur noch eine einzelne Reihe von Rasterpunkten in unserer Bounding-Box übrig ist. Von dieser Linie wählen wir dann zufällig einen Punkt. Wir benötigen O(log∆) Iterationen, da es ∆ viele vertikale Reihen mit Rasterpunkten gibt und jede Iteration benötigt O(log∆) um die Anzal der Rasterpunkte in einer Hälfte zu berechnen. So kommen wir insgesamt auf eine Laufzeit von O(log 2 ∆). 2 5.2 Erweiterter Suchbaum Wir hatten uns überlegt, dass wir eine Zusammenstellung von Sichtbarkeitspolygonen dazu benutzen können, um die Gewichte der Rasterpunkte so zu speichern, dass wir sie mit einem akzeptablen Aufwand pflegen können. Beim Speichern der Zusammenstellung ist es wichtig, dass wir zufällig aber 8 abhänging von ihren Gewichten einen Rasterpunkt wählen können. Außerdem müssen wir Sichtbarkeitspolygone der Zusammenstellung hinzufügen können, die Summe der Gewichte der Rasterpunkte in einem Sichtbarkeitspolygon berechnen und sie danach evt. verdoppeln können. Zum Speichern der Zusammenstellung werden wir mehrere erweiterte Suchbäume verwenden. Wie wir die Suchbäume benutzen ist nach Lemma 7 beschrieben. Lemma 7 Sei S = {(x1 , w1 ), ..., (xm , wm )} eine Menge mit m Punkten auf einer Linie, zum Beispiel auf einer Kante eines Polygons. Jedem Punkt xi ist ein Gewicht wi zugeordnet. Dann gibt es einen erweiterten Suchbaum T , der für jede der folgenden Operationen nur O(log m) Zeit benötigt. • einf ügen(xi , wi ) - Fügt einen neuen Punkt xi mit dem Gewicht wi in S ein. • ändern(xi , wi ) - Ändert das Gewicht von Punkt xi in wi . • wählen() - Wählt einen Punkt xi zufällig aus S, mit der Wahrscheinlichkeit Pnwi w . j=1 j • intervalSumme(x, y) - Berechnet die Summe der Gewichte der Punkte S ∩ [x, y]. • intervalV erdoppeln(x, y) - Verdoppelt das Gewicht von jedem Punkt in dem Intervall S ∩ [x, y]. Beweis. Wir verwenden einen sortierten und balancierten Baum T . Die Höhe des Baumes ist in O(log m), da er balanciert ist und weil er sortiert ist, können wir einen Punkt xi finden, indem wir einmal von der Wurzel zum Blatt hinuntersteiten, was natürlich in Zeit O(log m) geht. Wir bezeichnen mit π(ν, µ) den Pfad von dem Knoten ν zum Knoten µ, wobei ν ein Vorfahre von µ ist. Jedes Blatt repräsentiert genau einen Punkt xi aus der Menge S. Das Blatt, welches den Punkt xi speichert, werden wir im Folgenden auch xi nennen. Jeder interne Knoten µ speichert zusätzlich ein Multiplikationsfaktor Mµ und ein Gewicht σµ . Der Multiplikationsfaktor Mµ ist zu Beginn 1 und er wird dazu verwendet, die Gewichte des ganzen Teilbaums zu verdoppeln. Jeder Knoten µ kennt auch das Gewicht seines Teilbaumes, das vorallem durch σµ repräsentiert wird. Wir aktualisieren die Multiplikationsfaktoren Mµ so, dass immer folgendes gilt: Y wi = Mξ ξ ∈ π(root(T ), xi ) Das Gewicht σµ ist definiert als: σµ = X Y xi Blatt im T eilbaum von µ 9 ξ ∈ π(µ, xi ) Mξ So lässt sich das Gewicht des Teilbaums unter den Knoten µ schnell durch die Multiplikationsfaktoren auf dem Pfad von der Wurzel bis zum Knoten µ und dem Gewicht σµ berechen. Y Gewicht des T eilbaums unter µ = σµ · Mξ (1) ξ ∈ π(root(T ), parent(µ)) Jetzt zeigen wir, dass die Operation wählen in Zeit O(log m) geht. Angenommen, wir haben uns bereits dafür entschieden, dass der Punkt xi den wir auswählen wollen, im Teilbaum Tµ unter dem Knoten µ liegt. Dann müssen wir jetzt entscheiden, ob wir ein Blatt aus dem linken Teilbaum Tlef t(µ) wählen oder nicht. Damit die Auswahl zufällig aber gleichmäsig nach den Gewichten verteilt geschieht, müssen wir die Wahrscheinlichkeit für die Wahl des linken Teilbaums anhand der Gewichte berechnen. Die Wahrscheinlichkeit ergibt sie wie folgt: P Gewicht der Blätter von Tlef t(µ) P = Gewicht der Blätter in Tµ Q σlef t(µ) ξ Q σµ ξ ∈ π(root(T ), lef t(µ)) Mξ ∈ π(root(T ), µ) Mξ = σlef t(µ) Mlef t(µ) σµ Da alle benötigten Werte zur verfügung stehen reicht es, den Baum einmal hinabzusteigen, um zufällig einen Punkt zu wählen. Damit ist die Laufzeit O(log m) Um die Laufzeit für intervalSumme(x, y) und intervalV erdoppeln(xy) zu beweisen, definieren wir die Menge X . Sei X die Menge aller Knoten µ, von denen alle Blätter im Intervall [x, y] liegen, aber für deren Vaterknoten diese Eigenschaft nicht gilt. Es ist klar, dass wir alle Knoten der Menge X in O(log m) besuchen können. Für die Operation intervalV erdoppeln(xy) reicht es, wenn wir für jeden Knoten µ ∈ X den Multiplikationsfaktor Mµ verdoppeln. Da jedes Blatt im Intervall [x, y] unter genau einem Knoten aus X liegt, haben wir dadurch alle Werte der Blätter in diesem Intervall verdoppelt. Da wir die Knoten alle in Zeit O(log m) besuchen können, geht die gesamte Operation auch in O(log m) Zeit. Für die Operation intervalSumme(x, y) benutzen wir wieder die Menge X . Wir müssen die Summe der Gewichte aller Blätter in Intervall [x, y] berechnen. Da jedes Blatt unter genau einem Knoten in X liegt reicht es, wenn wir für jeden Knoten µ ∈ X mit der Gleichung (1) das Gewicht seines Teibaums ausrechnen und die so erhaltenen Gewichte summieren. Da wir alle Knoten in X in Zeit O(log m) besuchen können und da alle für die Gleichung 10 (1) benötigten Werte ohne zusätzlichen Aufwand zur Verfügung stehen, lässt sich die Operation intervalSumme(x, y) in O(log m) Zeit ausführen. Es bleibt die Laufzeit für die Operationen einf ügen(xi , wi ) und ändern(xi , wi ) zu beweisen. Um den Knoten xi einzugügen, wird er ganz normal in den Suchbaum eingefügt und der Baum anschließend balanciert. Das geht natürlich in O(log m). Die folgenden Schritte sind für beide Operationen gleich. Sei µ der Knoten in dem xi gespeichert ist. Dann müssen wir den Multiplikationsfaktor diese Knotens aktualisieren. Wir setzen ihn wie folgt: wi Mµ = Q ξ ∈ π(root(T ), parent(µ)) Mξ Damit hat unser Blatt den richtigen Wert. Aber daduch das sich in diesem Blatt der Wert geändert hat stimmen die σµ́ der Knoten µ́ auf dem Weg von der Wurzel zum Blatt µ nicht mehr. Daher aktualisieren wir alle Knoten µ́ ∈ π(root(T ), µ) von unten nach oben. Insgesammt müssen wir dazu den Baum nur einmal runter und wieder rauf laufen, also benötigen wir auch hier nur O(log m) Zeit. 2 5.3 Verwendung der Datenstruktur Als nächstes beantworten wir die Frage, wie man die Zusammenstellung A und die Gewichte mit Hilfe der vorgestellten Datenstruktur speichert. Die Zusammenstellung wird während des Algorithmus in jeder Iteration um ein Sichtbarkeitspolygon erweitert. Mit Ai bezeichnen wir die Zusammenstellung, die in der i-ten Iteration durch das Hinzufügen eines Sichtbarkeitspolygons entsteht. Die Fläche des Polygons wird durch die Kanten der Sichtbarkeitspolygone in kleinere Flächen geteilt. Eine zusammenhängende Fläche in P nennen wir eine Zelle. Der Einfachheithalber nehmen wir an, das jede Zelle ein Dreieck ist. Falls dem nicht so ist, berechnen und speichern wir für diese Zelle eine Triangulation. Dies beeinträchtigt die Gesamtlaufzeit des Algorithmus nicht. Wenn wir die Zusammenstellung Ai betrachten, sehen wir, dass jede der 11 Kanten der Zusammenstellung auf einer Kante eines der Sichtbarkeitspolygone V is(qj ) mit j = 1, ..., i liegt. Wobei qj jeweils der Punkt ist, für den wir in der i-ten Iteration V is(qj ) der Zusammenstellung Ai−1 hinzugefügt haben. Die Kanten der Sichtbarkeitspolygone nennen wir Lange-Kanten. Jede Lange-Kante ersetzen wir durch zwei Kopien von ihr. Diese Kanten nennen wir Polygon-Kanten. Die zwei Kopien benötigen wir, damit jede jeweils nur Zellen der Zusammenstellung auf einer Seite begrenzt. Zum Speichern der Zusammenstellung werden wir für jede Polygon-Kante einen erweiterten Suchbaum anlegen. Unser Suchbaum speichert Punkte auf einer Linie und dazu jeweils ein Gewicht. Punkte sind in der Zusammenstellung alle Schnittpunkte von Geraden. Jeder Schnittpunkt wird insgesamt 8 mal gespeichert. Das liegt daran, dass jeder Schnittpunkt zu vier PolygonKanten gehört. Und für jede Polygon-Kante speichern wir den Schnittpunkt zweimal, jeweils für die linke und rechte angrenzende Zelle. Dies machen wir, da die Rasterpunkte in den beiden Zellen verschiedene Gewichte haben können. Ein Beispiel dazu gibt das folgende Bild. Für eine Lange-Kante sind alle Schnittpunkte durch große grünen Punkt dargestellt. Und für einen Schnittpunkt ist rechts unten die Aufteilung eines Schnittpunktes in die 8 zu speichernden Punkte angedeutet. Man sieht auch, dass pro Polygon-Kante genau ein Punkt zu genau einer Zelle gehört. Das ist wichtig zum Speichern der Gewichte. Das Gewicht, das zu einem Punkt gespeichert wird, der zur Zelle c gehört, wc . Wobei wc das Gesamtgewicht der Punkte in der Zelle c ist und mc ist 2m c die Anzahl der Eckpunkte die die Zelle c hat. Zusätzlich zu jedem Suchbaum jeder Polygon-Kante speichern wir einen erweiterten Suchbaum T̃ . In diesem Suchbaum speichern wir für jede PolygonKante ei einen repräsentativen Punkt xi zusammen mit dem Gesamtgewicht 12 der Kante ei . Das Gesamtgewicht der Kante ei ist gleich der Summe der Gewichte aller im Suchbaum zu ei gespeicherten Punkte. Zu Beginn des Algorithmus initialisieren wir unsere Datenstruktur, indem wir die Zusammenstellung A0 , also das Polygon P, speichern. Wir legen zu jeder Kante von P ein Suchbaum an, in dem wir den Start- und Endpunkt der Kante speichern. Da wir bis jetzt nur eine Zelle haben, hat jeder Punkt das gleiche Gewicht. Es ergibt sich aus der Anzahl der Rasterpunkte in P geteilt durch das zweifache der Kantenzahl. In den Suchbaum T̃ speichern wir z.B. zu jeder Kante von P den Startpunkt zusammen mit dem Gewicht der zugehörigen Kante. Für den Algorithmus benötigen wir die Möglichkeit zufällig einen Rasterpunkt zu wählen. Die Wahl muss aber abhängig von den Gewichten der Rasterpunkte sein. Diese Aktion ist durch unsere Datenstruktur möglich. Um einen Rasterpunkt zu bekommen, rufen wir als erstes die Operation wählen() für den Baum T̃ auf. Dadurch haben wir eine Polygon-Kante e erhalten. Als zweites rufen jetzt die Operation wählen() für den Baum T der Kante e auf. So erhalten wir eine Zelle. Die beiden Operationen haben sichergestellt, dass unsere Wahl zufällig aber abhänging von den Gewichten ist. Als drittes müssen wir jetzt nur noch zufällig einen der Punkte der Zelle auswählen. Da alle Punkte der Zelle das gleiche Gewicht haben, reicht uns diesmal eine rein zufällige Wahl. Jetzt wissen wir, wie wir unsere Wächer wählen können. Wenn wir den von den Wächtern eingesehenen Bereich von P ausgerechnet haben und einen Punkt qj ausserhalb dieses Bereiches aber noch in P gewählt haben, müssen wir den Rand von V is(qj ) unserer Zusammenstellung hinzufügen. Dazu gehen wir wie folgt vor: Als erstes müssen wir eine Zelle c in Ai−1 finden, die einen Punkt von ∂V is(qi ) enthält, der auch ein Punkt von P ist. Um c einfach zu finden, speichern wir uns zu jedem Punkt von P in welcher Zelle er liegt. Dann finden wir c, indem wir prüfen, welcher Punkt von p den Punkt qi sieht. Als nächstes folgen wir von Punkt p aus dem ∂V is(qi ) durch die Zusammenstellung Ai−1 . Jede Zelle, die wir beim Verfolgen des Randes schneiden, teilen wir in zwei Hälften. Für die beiden Hälften berechnen wir, wieviel Punkte es in den beiden neuen Zellen gibt. Für jeden Punkt xi , der zu der geteilten Zelle gespeichert war, aktualisieren wir das Gewicht durch den Aufruf der Operation ändern(xi , wi ), wobei wi das neue Gewicht ist. Ausserdem müssen wir die Anzahl der Punkte der beiden Zellen aktualisieren. Auf dem folgenden Bild ist an einem Beispiel dargestellt, wie ein ∂V is(qi ) in eine Zusammenstellung eingefügt wird. Links ist die Zusammenstellung Ai−1 zu sehen. In der Mitte sind die neuen Kanten vom ∂V is(qi ) zu sehen. 13 V is(qi ) ist grau hinterlegt. Rechts sieht man die Zusammenstellung Ai . In ihr sind alle Kanten grau hinterlegt, die beim Einfügen von ∂V is(qi ) aktualisiert werden mussten. Die zum Berechnen des Gewichts und zum Verdoppeln des Gewichts aufgerufenen Funktionen werden für alle grau hinterlegten Kanten, jeweils mit den Koordinaten der beiden äußersten schwarzen Punkte, aufgerufen. Auf dem Bild war bereits die nächste Aktion angedeutet. Nachdem man ∂V is(qi ) der Zusammenstellung hinzugefügt hat, wird im Algorithmus überprüft, ob das Gewicht der Rasterpunkte innerhalb von V is(qi ) um einen bestimmten Faktor kleiner ist, als das Gesamtgewicht des Polygons. Um das Gewicht von V is(qi ) zu berechnen, rufen wir für jede Kante, die V is(qi ) scheidet oder begrenzt, die Operation intervalSumme(x, y) auf. Dabei sind x und y die beiden Schnittpunkte der Kante mit ∂V is(qi ). Das Gesmtgewicht des Polygons erhalten wir mit dem Suchbaum T̃ , indem wir die Summe der Gewichte aller im Suchbaum gespeicherten Punkte bilden. Falls die Überprüfung positiv verläuft, müssen wir die Gewichte aller Rasterpunkte in V is(qi ) verdoppel. Dazu rufen wir auf den gleichen Kanten und mit den gleichen Punkten wie zuvor die Operation intervalV erdoppeln(x, y) auf. 5.4 Der Algorithmus Betrachten wir den Algorithmus 5.1 als Ganzes. Er ist auf der Seite 5 abgebildet.Der grobe Ablauf des Algorithmuses ist gleich wie der des Algorithmus 3.1. In der äußeren Schleife wird die Funktion ComputeGuards(P, k) aufgerufen. Die Funktion ComputeGuards(P, k) versucht für das Polygon P eine Menge von O(k log k) vielen Wächtern zu finden. Die Positionen der 14 Wächter sind dabei auf das Raster Γ beschränkt. Als erstes initialisiert die Funktion ComputeGuards(P, k) die Datenstruktur für den Algorithmus. Dazu gehören n Suchbäume für die n Kanten von P und ein zusätzlicher Suchbaum in dem ein Punkt für jede der n Kanten gespeichert wird. Damit ist die Zusammenstellung A0 gegeben. Als nächstes beginnt die innere Schleife. In ihr wird zunächst eine Menge G ⊆ Γ von Wächtern bestimmt, wie im vorherigen Kapitel beschrieben. Wenn die Menge G ganz P sieht ist der Algorithmus zuende. Sieht die Menge G nicht das ganze Polygon P, wählt man zufällig einen Punkt q aus einem Teil des Polygons der nicht gesehen wird. Für diesen Punkt fügt man das Sichtbarkeitspolygon Vis(q) der Zusammenstellung Ai−1 hinzu, was ebenfalls im vorherigen Kapitel beschrieben ist. Die Variable i gibt hierbei an, um welche Iteration es sich handelt. Falls das k-fache des Gewichts des Sichtbarkeitspolygons kleiner oder gleich dem Gewicht des gesamten Polygons ist, wird das Gewicht des Sichtbarkeitspolygons verdoppelt. Falls die Schleife O(k log nk ) durchläufe macht, ohne das eine Menge G gefunden wurde, die P ganz sieht, gibt die Funktion die leere Menge zurück. Daraufhin wird in der äußeren Schleife das k verdoppelt und die Funktion ComputeGuards(P, k) erneut aufgerufen. Die äußere Schleife des Algorithmus 5.1 macht eine exponentielle Suche nach copt , wodurch die Funktion ComputeGuards(P, k) insgesamt O(log copt ) mal aufgerufen wird. Ein Aufruf von ComputeGuards(P, k) macht O(k log nk ) Iterationen. Die i-th Iteration hat einen Aufwand von O(niα(n) log n (log i+ log 2 ∆)). Damit kommt man für den Algorithmus insgesamt auf eine Laufzeit von O(nc2opt log n log(ncopt ) log 2 ∆). 15 Algorithmus 5.1 Bestimmung der Wächter auf einem Raster // P ist das einfache Polygon, für das die Wächter bestimmt werden. // Falls copt unbekannt ist, wird k mit 1 initialisiert. k := 1; repeat G := ComputeGuards(P, k); if G 6= ∅ then Berichtet die Wächter G; else k := k + k ; // da k zu klein war. end if until Eine Menge von Wächtern gefunden wurde. ComputeGuards(P, k){ Initialisierung der Datenstruktur; for i = 1 to O(k log( nk )) do Bestimme eine Menge G ⊆ Γ wie in Abschnitt 5.3 beschrieben; if Die Punkte von G sehen ganz P then return G; else Suche einen Punkt q ∈ P der nicht von G sichtbar ist; Füge V is(q) in die Zusammenstellung Ai−1 ein; if 2k Gewicht von V is(q) ≤ Gewichte von P then Verdopple die Gewichte der Rasterpunkte in V is(q); end if end if end for return ∅ } 16 6 Polygone mit Löchern Die in den vorherigen Kapiteln vorgestellten Algorithmen können leicht erweitert werden, so dass sie Sichtbarkeitsprobleme in komplizierteren Gallerien oder mit anderen Modellen für die Sichtbarkeit lösen. In den vorgestellten Algorithmen konnten die Wächter unendlich weit sehen und hatten einen Blickwinkel von 360◦ . Wenn die Wächter Menschen währen, so müsste man die Sichtweite und den Blickwinkel einschränken, um eine realistische Lösung zu finden. Wenn wir unsere Algorithmen auf ein solches eingeschränktes Sichbarkeitsmodell ändern wollen, müssen wir lediglich die Berechnung der Sichtbarkeitspolygone ändern. Im Folgenden ist die Erweiterung der Algorithmen für Polygone mit Löchern beschrieben. Dabei wird wieder das Standardmodell für die Sichtbarkeit angenommen. 6.1 Sichtbarkeit in Polygonen mit Löchern Wir betrachten ein Polygon P mit n Ecken und h Löchern. Durch die Löcher wächst die Komplexität der Zusammenstellung aus den Rändern von k Sichtbarkeitspolygonen auf O(nk 2 h) erhöht. Bei Polygonen ohne Löcher war sie O(nk 2 ). Der Rand eines Sichtbarkeitspolygons besteht aus n+h Kanten, die nicht auf dem Rand des Polygons liegen. Zwei verschiedene Sichtbarkeitspolygone schneiden sich maximal in 2h Punkten. k viele Sichtbarkeispolygone schneiden sich demnach in maximal (k+1)kh, also O(k 2 h) vielen Punkten. So kommen wir insgesamt auf die angegebene Komplexität. In [6] wurde gezeigt, dass die VC-dimension dieses Problems in θ(1 + log h) ist. Durch das Anwenden der Erkentnisse aus [2] sehen wir, dass sich der Approximationsfaktor auf O(log h log(copt log h)) erhöht. Fügen wir das zusammen und erweitern wir den Algorithmus aus Abschnitt 5, so kommen wir zu folgendem Ergebnis. Theorem 8 Sei P ein Polygon mit n Ecken und h Löchern. Es ist möglich, eine Menge G von O(copt log n log(copt log n)) Eckpunkten von P zu finden, die ganz P sehen, wobei copt die Kardinalität der optimalen Lösung ist. Die erwartete Laufzeit ist O(nhc3opt polylog n). Sei Γ ein Raster in P. Dann kann man eine Menge G von O(copt log h log(copt log n)) Punkten aus Γ finden die ganz P sehen. Die erwartete Laufzeit ist O(nhc3opt polylog n log 2 ∆), wobei ∆ die Differenz aus dem Durchmesser von P und der Rastergröße ist. 17 Literatur [1] S. Basu, R. Pollack, and M.-F.Roy. On the combinatorial and algebraic complexity of quantifier elimination. J. ACM, 43:1002–1045, 1996. [2] H. Brönnimann and M. T. Goodrich. Almost optimal set covers in finite vc-dimension. Discrete Comput. Geom. 14, pages 263–279, 1995. [3] A. Efrat and S. Har-Peled. Guarding galleries and terrains. 2006. [4] S. Kahan and J. Snoeyink. On the bit complexity of minimum link paths: Superquadratic algorithms for problems solvable in linear time. In Proc. 12th Annu. ACM Sympos. Comput. Geom., pages 151–158, 1996. [5] J. O’Rourke. Art gallery theorems and algorithms. The International Series of Monographs on Computer Science. Oxford University Press, New York, NY, 1987. [6] P. Valtr. Guarding galleries where no point sees a small area. Israel J. Math, pages 1–16, 1998. [7] D. Varberg. Pick’s theorem revisited. The American. Math. Monthly 92., pages 584–587, 1985. 18