miałem podobny problem i skończyło się go rozwiązać w ten sposób:
Moja struktura danych jest wykonana z dependends
słownika, z identyfikatorem węzła do listy węzłów, które zależą od niego (tj swoich zwolenników w. DAG). Zauważ, że działa tylko dla DAG - to jest skierowany, acykliczny wykres.
Nie obliczałem dokładnej złożoności, ale połknąłem mój wykres kilku tysięcy w ułamku sekundy.
_transitive_closure_cache = {}
def transitive_closure(self, node_id):
"""returns a set of all the nodes (ids) reachable from given node(_id)"""
global _transitive_closure_cache
if node_id in _transitive_closure_cache:
return _transitive_closure_cache[node_id]
c = set(d.id for d in dependents[node_id])
for d in dependents[node_id]:
c.update(transitive_closure(d.id)) # for the non-pythonists - update is update self to Union result
_transitive_closure_cache[node_id] = c
return c
def can_reduce(self, source_id, dest_id):
"""returns True if the edge (source_id, dest_id) is redundant (can reach from source_id to dest_id without it)"""
for d in dependents[source_id]:
if d.id == dest_id:
continue
if dest_id in transitive_closure(d.id):
return True # the dest node can be reached in a less direct path, then this link is redundant
return False
# Reduce redundant edges:
for node in nodes:
dependents[node.id] = [d for d in dependents[node.id] if not can_reduce(node.id, d.id)]
Czy możemy zamiast tego uznać B ---> C za zbędny? –
Czy redundant oznacza "krawędź X-> Y jest zbędna, jeśli istnieje ścieżka bez krawędzi od X do Y" lub czy po prostu szukasz drzewa opinającego? –
@Zach: Nie, B-> C nie jest zbędny, ponieważ jeśli zostanie usunięty, nie ma ścieżki w wynikowym wykresie od B do C. – ShreevatsaR