Gezielter Gewerkschaftsfund


11

Stellen Sie sich einen gerichteten Graphen G in dem Sie dynamisch Kanten hinzufügen und bestimmte Abfragen durchführen können.

Beispiel: disjunkte Gesamtstruktur

Betrachten Sie die folgenden Abfragen:

arrow(u, v)
equiv(u, v)
find(u)

der erste fügt dem Graphen einen Pfeil hinzu uv, der zweite entscheidet, ob uv , der letzte findet einen kanonischen Vertreter der Äquivalenzklasse von , dh a r(u) so dass uv impliziert r(v)=r(u) .

Es gibt einen bekannten Algorithmus, der die disjunkt gesetzte Walddatenstruktur verwendet, die diese Abfragen in quasikonstanter amortisierter Komplexität implementiert, nämlich . Beachten Sie, dass in diesem Fall mit implementiert wird .O(α(n))equivfind

Komplexere Variante

Jetzt interessiert mich ein komplexeres Problem, bei dem die Anweisungen eine Rolle spielen:

arrow(u, v)
confl(u, v)
find(u)

Der erste fügt einen Pfeil , der zweite entscheidet, ob es einen Knoten w gibt, der sowohl von u als auch von v aus erreichbar ist , dh u v . Der letzte sollte ein Objekt r ( u ) zurückgeben, so dass u v r ( u ) r ( v ) impliziert, wobei leicht berechenbar sein sollte. (Um beispielsweise zu berechnenuvwuvuvr(u)uvr(u)r(v)confl). Ziel ist es, eine gute Datenstruktur zu finden, damit diese Operationen schnell sind.

Fahrräder

Das Diagramm kann Zyklen enthalten.

Ich weiß nicht, ob es eine Möglichkeit gibt, die stark verbundenen Komponenten effizient und inkrementell zu berechnen, um nur DAGs für das Hauptproblem zu berücksichtigen.

Natürlich würde ich mich auch über eine Lösung für DAGs freuen. Dies würde einer inkrementellen Berechnung des am wenigsten verbreiteten Vorfahren entsprechen.

Naiver Ansatz

Die disjunkt gesetzte Gesamtstrukturdatenstruktur ist hier nicht hilfreich, da die Richtung der Kanten nicht berücksichtigt wird. Beachten Sie, dass kein einzelner Knoten sein kann, falls der Graph nicht konfluent ist.r(u)

Man kann definieren und definieren als S 1S 2 , wenn S 1S 2 & ne; . Aber wie berechnet man das inkrementell?r(u)={vuv}S1S2S1S2

Wahrscheinlich ist die Berechnung einer so großen Menge nicht sinnvoll, eine kleinere Menge sollte interessanter sein, wie beim üblichen Algorithmus zum Finden von Vereinigungen.

Antworten:


3

( Bearbeiten : habe meine Antwort jetzt komplett neu geschrieben, da mein Verständnis des Problems (ich hoffe) klarer ist.)

Es hört sich so an, als könne dieses Problem darauf reduziert werden, schrittweise eine Annäherung an den transitiven Abschluss des Graphen zu erstellen und zu verbessern, während der Graph erstellt und durchsucht wird.

ist abstrakt die Menge aller Knoten, die sowohl von u als auch von v für jedes v u im Graphen erreichbar sind. (Natürlich haben nicht alle u , v- Paare notwendigerweise einen Knoten, der von beiden aus erreicht werden kann.) Anders als bei union-find kann diese Menge im Diagramm nicht als kanonischer repräsentativer Knoten dargestellt werden, da Es kann Knoten geben, die sowohl von u als auch von v und sowohl von u als auch von w aus erreichbar sind und dennoch nicht von v und w aus erreichbar sind.r(u)uvvuu,vuvuwvw

Angenommen, Sie pflegen für jedes eine Reihe von Knoten, die von u aus erreichbar sind (ich nenne dies R ( u ) ). Diese Sätze wären notwendigerweise eine zusätzliche Datenstruktur für jeden Knoten oder zumindest ein Satz zusätzlicher "Verknüpfungs" -Kanten im Diagramm. Wenn Sie die angegebene Struktur des Diagramms nicht beibehalten möchten, müssen Sie nicht zwischen diesen Kanten und den angegebenen Kanten unterscheiden.uuR(u)

Ich habe keine Ideen für eine Datenstruktur, die diese erfasst, die effizienter als der allgemeine Fall ist (z. B. ein Bitvektor oder eine Hash-Tabelle), aber Sie können diese Sätze schrittweise aktualisieren:

Jedes Mal, wenn Sie eine Kante von zu einem anderen Knoten v hinzufügen , setzen Sie R ( u ) = R ( u ) R ( v ) .uvR(u)=R(u)R(v)

Implementieren Sie, conflindem Sie zuerst versuchen . Wenn dies nicht leer ist, geben Sie true zurück. Wenn es jedoch leer ist, führen Sie zwei parallele Breitensuchen von R ( u ) und R ( v ) durch, bis Sie entweder beide erreichbaren Mengen erschöpft haben oder einen gemeinsamen Knoten finden. Aktualisieren Sie dabei auch R ( u ) und R ( v ) (und die Rs aller gefundenen Zwischenknoten), um die erreichbaren Knoten einzuschließen, die Sie gefunden haben.R(u)R(v)R(u)R(v)R(u)R(v)Rund wenn Sie einen gemeinsamen Knoten finden, setzen Sie R (u) = R (v) = R (u) \ cup R (v) .

find(u)gibt nur . Das Problem ist, dass nicht nur in Bezug auf implementiert wird . Ich sehe nicht ein, wie es möglicherweise sein könnte, wenn der Algorithmus nicht nicht inkrementell war (dh alle R- Sätze aller Knoten mit dem transitiven Schließen des Graphen vorberechnen ). Der inkrementelle Ansatz sollte jedoch immer noch eine ziemlich gute Amortisation ergeben Kosten, obwohl ich keine Ahnung habe, ob es sich O ( α ( n ) ) ohne weiteres nähert. ( Dies ist wahrscheinlich nicht der Fall. Eine falsche Antwort von erfordert, dass Sie zwei BFS starten, auch wenn Ihre R- Sätze gesättigt sind. Dies scheint auch unvermeidlich, es sei denn, der Algorithmus ist nicht inkrementell.)R(u)conflfindRO(α(n))conflR

Dies klingt sehr nach einem Sonderfall der Methoden von La Poutré und van Leeuwen zur Aufrechterhaltung des transitiven Schließens eines Graphen .

R


Vielen Dank für Ihre Antwort. Ich hoffe, ich habe meine Frage jetzt klarer formuliert: Ich kümmere mich nicht um verbundene Komponenten (aber die starken CCs könnten für die endgültige Lösung hilfreich sein). Ich habe nicht r(u) noch und das r(u)kann kein einzelner Knoten in einer DAG sein.
jmad

OK, das ist etwas klarer. Es scheint sor(u) ist abstrakt die Menge aller Knoten, die von beiden erreichbar sind u und vfür jeden vuin der Grafik. Dieser Satz kann ein Satz von "Verknüpfungs" -Kanten seinu, I think, and then this begins to look like computing the transitive closure of reachability in the graph. I still don't immediately see why this couldn't be done incrementally (compress paths as you find them) although it would likely require more storage/work (label/update all "shortcut" edges) than union-find. Does this make sense?
Chris Pressey

Assuming transitive closure is a fair way to characterize r(u), this sounds like it would be closely related: en.wikipedia.org/wiki/…
Chris Pressey

I don't think confl(u,v) should merge R(u) and R(v). It could modify them, but that would be already done by the call to find, like in the disjoint-set forest method.
jmad

You're right that it shouldn't merge them; I'll edit the answer. But calls to find really can't compute anything useful, because there is no unique object to "find" except r(u), which R(u) approximates. (How would find know what to look for, to make updates? It is only given u but the information in R(u) potentially applies to every other node in the graph.)
Chris Pressey
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.