1 Algoritmo de Pesquisa em Profundidadevoid dfs( Vertex v ) //Depth-first search { v.visited = true; for each w adjacent to v if( ! w.visited ) dfs( w ); } Esquema básico da pesquisa em profundidade generalização da travessia em pré-ordem começando num vértice v, processa-se v e depois atravessa-se recursivamente todos os vértices adjacentes a v executada numa árvore — visita sistemática de todos os vértices, tempo O(|E|) executada num grafo arbitrário evitar os ciclos marcar os nós visitados para impedir a repetição grafo não dirigido/não conexo ou dirigido/não fortemente conexo: ficando vértices por visitar percorrer lista de nós até ao seguinte não marcado
2 1 - Grafos não dirigidos A aresta de retorno para nó já visitado A B BC grafo árvore de expansão em profundidade C D E um grafo não dirigido é conexo Û uma pesquisa em profundidade a começar em qualquer nó visita todos os nós começa-se por marcar A; 1º adjacente: B; recorre… - ao processar (v,w), se w não estiver marcado acrescenta-se a aresta na árvore - se já estiverem ambos marcados, acrescenta-se uma aresta de retorno (a ponteado) que não pertence à árvore (todas as arestas do grafo estão na árvore total) árvore simula a pesquisa; numeração em pré-ordem pelas arestas da árvore dá a ordem de marcação dos vértices (numerar antes de aceder a adjacentes)
3 2 – Biconectividade e Pontos de ArticulaçãoGrafo conexo não dirigido é biconexo se não existe nenhum vértice cuja remoção torne o resto do grafo desconexo Aplicação - rede com tolerância a falhas Pontos de articulação - vértices que tornam o grafo desconexo (críticos) Algoritmo de detecção de pontos de articulação em tempo linear início num vértice qualquer pesquisa em profundidade, numerando os vértices ao visitá-los — Num(v), em pré-ordem para cada vértice na árvore de expansão calcular Low(v), o menor número de vértice que se atinge com zero ou mais arestas na árvore e possivelmente uma aresta de retorno (computável com travessia em pós-ordem)
4 Pontos de articulação Low(v) é mínimo de Num(v)o menor Num(w) de todas as arestas (v,w) de retorno o menor Low(w) de todas as arestas (v,w) da árvore Cálculo de Low(v) primeiro para os filhos e depois para o pai arestas (v,w) são da árvore se Num(v) < Num(w); de retorno no caso inverso basta percorrer a lista de adjacências; O( |E| + |V| ) Vértice v é ponto de articulação se tiver um filho w tal que Low(w) Num(v) A raiz é ponto de articulação sse tiver mais que um filho na árvore
5 Detecção de pontos de articulaçãografo árvores de expansão em profundidade B A A,1/1 C,1/1 C D F D,2/1 G,7/7 B,2/1 G E C,3/1 F,4/2 E,3/2 A,5/1 D,4/1 B,6/1 G,7/7 v, Num(v)/Low(v) E,5/4 F,6/4 Pontos de articulação: C e D
6 Numa só pesquisa em profundidade ...// Procura Pontos de Articulação usando dfs // Contador global e inicializado a 1 void findArt( Vertex v) { v.visited = true; v.low = v.num = counter++; //regra 1 for each w adjacent to v if( !w.visited ) //ramo da árvore w.parent = v; findArt(w); if(w.low >= v.num ) System.out.println(v, "Ponto de articulação"); v.low = min(v.low, w.low); //regra 3 } else if ( v.parent != w ) //aresta de retorno v.low = min(v.low, w.num); //regra 2 Combina o pré-processamento e o pós-processamento numa única passagem
7 3 - Circuitos de Euler Puzzle: desenhar as figuras abaixo sem levantar o lápis e sem repetir arestas; de preferência, terminando no mesmo vértice em que iniciar. Reformulação do problema em Teoria de Grafos: pôr um vértice em cada intersecção Caminho de Euler: caminho que visita cada aresta exactamente uma vez problema resolvido por Euler em 1736 e que marca o início da Teoria dos Grafos Circuito de Euler – caminho de Euler começa e acaba no mesmo vértice
8 Solução condição necessária• circuito de Euler: número de arestas convergentes em cada vértice é par - o ciclo entra tantas vezes em vértices quantas sai • caminho de Euler: idem, excepto possivelmente em dois vértices - o primeiro e o último; no caso de haver mais vértices com número ímpar de arestas é impossível condição suficiente • se se verificarem as condições acima, então existe circuito (caminho) de Euler método: pesquisa em profundidade O(|E| + |V| ) principal problema: fazer um curto-circuito e deixar arestas de fora correcção - procurar o primeiro vértice no caminho obtido que possua uma aresta não percorrida - lançar uma sub-pesquisa em profundidade - inserir o resultado no caminho principal (usar lista ligada) Ciclo Hamiltoniano: ciclo simples que visita todos os vértices? (vê-se depois)
9 Exemplo de um circuito Grafo: existe caminho de Euler1 3 4 5 2 Grafo: existe caminho de Euler 7 6 8 9 10 11 12 1 2 3 4 5 Depois de fazer caminho 5, 4, 10, 5 7 6 8 9 10 11 12
10 Exemplo de um circuito Depois de fazer caminho1 2 3 4 5 Depois de fazer caminho 5, 4, 1,3,7,4,11,10,7,9,3,4,10, 5 7 6 8 9 10 11 12 1 2 3 4 5 Depois de fazer caminho 5, 4, 1, 3, 2, 8, 9, 6, 3, 7, 4, 11, 10, 7, 9, 3, 4, 10, 5 7 6 8 9 10 11 12 Circuito de Euler:
11 4 - Grafos dirigidos A B G D C F H E J I(também) atravessáveis em tempo linear por pesquisa em profundidade (serve para detectar se grafo é acíclico) problema: se não for fortemente conexo, pesquisa em profundidade pode não visitar todos os nós Þ recomeçar a pesquisa num nó não visitado (nova raiz…) A B G D C F H E J I
12 Árvore de expansão B H G C F A J D I Epesquisa em profundidade induz uma árvore/floresta de expansão para além das arestas genuínas da árvore, há arestas para nós já marcados arestas de retorno para um antepassado — (A,B), (I,H) arestas de avanço para um descendente — (C,D), (C,E) arestas cruzadas para um nó não relacionado — (F,C), (G,F) • alguns algoritmos necessitam de distinguir estas categorias de arestas B H G C F A J D I E
13 Componentes fortemente conexosMétodo: pesquisa em profundidade no grafo G determina floresta de expansão, numerando vértices em pós-ordem (ordem inversa de numeração em pré-ordem) inverter todas as arestas de G — Gr segunda pesquisa em profundidade, em Gr, começando sempre pelo vértice de numeração mais alta ainda não visitado cada árvore obtida é um componente fortemente conexo, i.e., a partir de um qualquer dos nós pode chegar-se a todos os outros Prova mesmo componente Þ mesma árvore de expansão se dois vértices v e w estão no mesmo componente, há caminhos de v para w e de w para v em G e em Gr; se v e w não pertencerem à mesma árvore de expansão, também não estão no mesmo componente mesma árvore de expansão Þ mesmo componente i.e., há caminhos de v para w e de w para v ou, equivalentemente, se x for a raiz de uma árvore de expansão em profundidade, há caminhos de x para v e de v para x, de x para w e de w para x e portanto entre v e w como v é descendente de x na árvore de Gr, há um caminho de x para v em Gr, logo de v para x em G; como x é a raiz tem o maior número de pós-ordem na primeira pesquisa; portanto, na primeira pesquisa, todo o processamento de v se completou antes de o trabalho em x ter terminado; como há um caminho de v para x, segue-se que v tem que ser um descendente de x na árvore de expansão — caso contrário v terminaria depois de x; isto implica um caminho de x para v em G.
14 Componentes fortemente conexosA,3 B,6 G,10 D,2 C,4 F,5 H,9 E,1 J,8 I,7 Gr: obtido de G por inversão de todas as arestas Numeração: da travessia de G em pós-ordem
15 Componentes fortemente conexosG H B D E A I C J F Travessia em pós-ordem de Gr Componentes fortemente conexos: {G}, {H, I, J}, {B, A, C, F}, {D}, {E}