--- author: Raffaele Mignone title: Caratterizzazione della complessità di un algoritmo per la ricerca di cicli orientati in un grafo keywords: - Complessità - Grafo - Ciclo subject: Caratterizzazione della complessità papersize: a4 lang: it-IT --- # Ricerca di cicli orientati ## Traccia Scrivere un programma per la ricerca di directed cycles in un grafo orientato. ## Soluzione Il problema può essere risolto prendendo come base la ricerca in profondità classica. Ad essa deve essere aggiunto un modo per tenere memoria dei nodi presenti sul percorso che si sta esplorando. Ciò può essere fatto tramite l'uso di un array così come si è fatto per tenere traccia dei nodi visitati[^vertex-info]. [^vertex-info]: Nel caso specifico si è utilizzata una data class che conserva le informazioni `isVisited`, `isOnPath` e `previously`. ```{#lst:cycle .kotlin caption="Versione modificata della ricerca in profondità"} private fun dfs(graph: UndirectedGraph, vertex: Int) { graphInfo[vertex].isVisited = true graphInfo[vertex].isOnPath = true graph.adjacentVertex(vertex) .forEach { when { hasCycle() -> return@forEach !graphInfo[it].isVisited -> exploreChild(graph, vertex, it) graphInfo[it].isOnStack -> cycle = makeCycle(vertex, it) } } graphInfo[vertex].isOnPath = false } ``` Quando tra i vertici adiacenti a quello che si sta esplorando si trova un nodo già presente sul percorso vuol dire che è stato trovato un ciclo. La costruzione del ciclo viene mostrata nel @lst:makeCycle ```{#lst:makeCycle .kotlin caption="Memorizzazione dei vertici che danno origine ad un ciclo"} private fun makeCycle( start: Int, end: Int ): MutableCollection { val cycle = Stack() var currentVertex = start while (currentVertex != end) { cycle.add(currentVertex) currentVertex = graphInfo[currentVertex].previously } cycle.add(end) cycle.add(start) return cycle } ``` Infine la funzione `exploreChild` (@lst:exploreChild) semplicemente si occupa di settare il predecessore e di eseguire la ricerca in profondità sul nuovo vertice. ```{#lst:exploreChild .kotlin caption="Funzione per eseguire la ricerca in profondità su un vertice adiacente"} private fun exploreChild( graph: UndirectedGraph, parent: Int, child: Int ) { graphInfo[child].previously = parent dfs(graph, child) } ``` ## Complessità L'algoritmo per l'individuazione dei grafi mostrato precedentemente è sostanzialmente una versione modificata della ricerca in profondità e nel caso peggiore deve visitare tutti i nodi percorrendo tutti gli archi, per cui ha una complessità pari a $E + V$. ## Source code - [DirectedCycle](https://git.norangeb.it/norangebit-unisannio-computer-science/lm-tecniche-di-programmazione/src/branch/master/src/main/kotlin/it/norangeb/algorithms/graph/operations/DirectedCycle.kt)