A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Grafos - 1 Grafos oGrafo G = (V, E) V conjunto de vértices E conjunto de arestas (ou arcos) - cada aresta é um par de vértices (v, w), em que v, w V -

Apresentações semelhantes


Apresentação em tema: "Grafos - 1 Grafos oGrafo G = (V, E) V conjunto de vértices E conjunto de arestas (ou arcos) - cada aresta é um par de vértices (v, w), em que v, w V -"— Transcrição da apresentação:

1 Grafos - 1 Grafos oGrafo G = (V, E) V conjunto de vértices E conjunto de arestas (ou arcos) - cada aresta é um par de vértices (v, w), em que v, w V - se o par for ordenado, o grafo é dirigido, ou digrafo - um vértice w é adjacente a um vértice v se e só se (v, w) E - num grafo não dirigido com aresta (v, w) e, logo, (w, v) w é adjacente a v e v adjacente a w - as arestas têm por vezes associado um custo ou peso G1= (Cruzamentos, Ruas) G2 = (Cidades, Estradas)

2 Grafos - 2 Mais definições caminho sequência de vértices v 1, v 2, …, v n tais que (v i, v i+1 ) E, 1 i

3 Grafos - 3 Representação omatriz de adjacências a[u][v] = 1 sse (u, v) E elementos da matriz podem ser os pesos (sentinelas indicam não aresta) apropriada para grafos densos 3000 cruzamentos e troços de ruas (4 por cruzamento) de elementos na matriz!

4 Grafos - 4 Lista de adjacências oestrutura típica para grafos esparsos para cada vértice, mantém-se a lista dos vértices adjacentes vector de cabeças de lista, indexado pelos vértices espaço é O(|E| + |V|) pesquisa dos adjacentes em tempo proporcional ao número destes ografo não dirigido: matriz simétrica; lista com o dobro do espaço

5 Grafos - 5 Ordenação topológica impossível se o grafo for cíclico não é necessariamente única ( ) ou ( ) no exemplo anterior oalgoritmo simples: - descobrir um vértice sem arestas de chegada - imprimir o vértice - eliminá-lo e às arestas que dele saem - repetir o processo no grafo restante Indegree(v) é o número de arestas (w, v) passagem sequencial do vector é O(|V|); com |V| chamadas: tempo é O( |V| 2 ) Ordenação dos vértices de um DAG tal que, se existe um caminho de v para w, então v aparece antes de w

6 Grafos - 6 Versão ineficiente void topsort()throws CycleFound { Vertex v, w; for(int conta = 0; conta <= NUM_VERTEX; conta ++) { v = novo_Vertice_Indegree_Zero(); if( v == null ) throw new CycleFound() v.topNum = conta; for each w adjacent to v w.indegree--; }

7 Grafos - 7 Refinamento da ordenação topológica melhoria: em cada iteração, colocar numa fila (ou pilha) os vértices com indegree=0 em cada passo, é retirado da fila um qualquer dos vértices presentes ao actualizar o indegree na lista de adjacências do vértice a eliminar colocam- se na fila os que passam a ter indegree=0 inicialização põe na fila os vértices com indegree=0 à partida tempo de execução O(|E| + |V|) - o corpo do ciclo de actualização do indegree é executado no máximo uma vez por aresta - as operações na fila são executadas no máximo uma vez por vértice - a inicialização leva um tempo proporcional ao tamanho do grafo

8 Grafos - 8 Algoritmo refinado void topsort ()throws CycleFound { int counter = 0; Vertex v, w; Queue q; q= new Queue(); for each vertex v if ( v.indegree == 0 ) q.enqueue( v ); while( !q.isEmpty() ) { v = q.dequeue(); v.topNum = ++counter; for each w adjacent to v if( --w.indegree == 0 ) q.enqueue( w ); } if( counter != NUM_VERTEX ) throw new CycleFound(); }

9 Grafos - 9 Execução no grafo de exemplo indegree anterior a cada operação dequeue Vértice v v v v v v v enqueue v1v2v5v4v3,v7v6 dequeue v1v2v5v4v3v7v6

10 Grafos - 10 Caminho mais curto Dado um grafo pesado G = (V, E) e um vértice s, obter o caminho pesado mais curto de s para cada um dos outros vértices em G oExemplo: rede de computadores, com custo de comunicação e de atraso dependente do encaminhamento (o caminho mais curto de v7 para v6 tem custo 1) arestas com custo negativo complicam o problema ciclos com custo negativo tornam o caminho mais curto indefinido (de v4 a v7 o custo pode ser 2 ou -1 ou -7 ou …) oOutro exemplo: se o grafo representar ligações aéreas, o problema típico poderá ser: Dado um aeroporto de partida obter o caminho mais curto para um destino não há algoritmo que seja mais eficiente a resolver este problema do que a resolver o mais geral

11 Grafos Caminho não pesado opretende-se o comprimento dos caminhos: pode ser visto como um caso particular em que o peso de cada aresta é unitário começa-se por marcar o vértice inicial s com comprimento 0 sucessivamente, passa-se aos que lhe estão adjacentes e marcam-se com mais 1 do que o valor do caminho até ao antecedente progride-se por níveis, passando ao nível seguinte só depois de ter esgotado o anterior oeste tipo de pesquisa em grafos designa-se por pesquisa em largura semelhante à travessia por níveis de uma árvore ocódigo usa uma tabela em que regista, para cada vértice v - a distância de cada vértice ao inicial (dist) - se o vértice já foi processado (known) - qual o antecessor no caminho mais curto (path)

12 Grafos - 12 Evolução da marcação do grafo v1v2 v3 v4v5 v6v7 v1v2 v3 v4v5 v6v7 v1v2 v3 v4v5 v6v v1v2 v3 v4v5 v6v

13 Grafos - 13 Algoritmo básico void unweighted( Vertex s) { Vertex v, w; s.dist = 0; for(int currDist = 0; currDist < NUM_VERTEX; currDist++) for each vertex v if( !v.known && v.dist == currDist ) { v.known = true; for each w adjacent to v if( w.dist == INFINITY ) { w.dist = currDist + 1; w.path = v; }

14 Grafos - 14 Eficiência do algoritmo básico tempo de execução O(|V|^2), devido aos ciclos for encaixados oremoção da ineficiência semelhante à da ordenação topológica em cada momento, só existem dois tipos de vértices não processados com Dist - os do nível corrente ( dist = currDist ) ainda não processados e os adjacentes a estes já marcados no nível seguinte ( dist= currDist+1 ) podiam guardar-se em duas caixas diferentes mas, como só se marca o primeiro do nível seguinte depois de ter todos os do nível corrente, basta usar uma fila o atributo known não é usado nesta solução

15 Grafos - 15 Algoritmo refinado otempo de execução é O(|E| + |V|), com grafo representado por lista de adjacências void unweighted( Vertex s) { Vertex v, w; Queue q; q= new Queue(); q.enqueue (s); s.dist = 0; while( !q.isEmpty() ) { v = q.dequeue(); v.known = true; //agora desnecessário for each w adjacent to v if( w.dist == INFINITY ) { w.dist = v.dist + 1; w.path = v; q.enqueue( w ); } }}

16 Grafos - 16 Evolução da estrutura de dados v v v 3 1 1v 3 11v 3 v v 1 0 2v 1 v v v 1 0 2v 1 v v v 3 01v 3 11v 3 v Q v3v3 v 6, v 2, v 4 v 2, v 4 v 1, v 6 Início Visita v 3 Visita v 1 Visita v 6 knownd v p v

17 Grafos - 17 Evolução da estrutura de dados v v 1 11v 3 11v 3 1 1v 3 11v 3 v 2 1 2v 1 1 2v 1 1 2v 1 1 2v 1 v v 4 0 2v 1 1 2v 1 1 2v 1 1 2v 1 v 5 0 3v 2 0 3v 2 1 3v 2 1 3v 2 v 6 11v 3 11v 3 11v 3 11v 3 v v 4 0 3v 4 0 3v 4 Q v7v7 (vazia)v 5, v 7 Visita v 4 Visita v 5 Visita v 7 Knownd v p v v 4, v 5 Visita v 2

18 Grafos Caminho pesado oa solução é uma modificação da anterior cada vértice mantém uma distância ao inicial, obtida somando pesos nos caminhos quando se declara um vértice known, exploram-se os seus adjacentes; se o caminho através deste nó é melhor que o já registado, modifica-se este distância corrente em cada vértice: a melhor usando apenas vértices já processados o ponto crucial: escolher para declarar known o vértice que tiver o menor custo até ao momento é o único cujo custo não pode diminuir todas as melhorias de caminhos que usam este vértice são exploradas oeste é um exemplo de um algoritmo ganancioso: em cada passo faz o que melhora o ganho imediato orestrição: só é válido se não existirem custos negativos oregista-se o vértice antecedente, responsável directo pelo custo estimado; seguindo a sequência recupera-se o caminho mínimo

19 Grafos - 19 Estádios do algoritmo de Dijkstra v1v2 v3 v4v5 v6v v1v2 v3 v4v5 v6v v1v2 v3 v4v5 v6v v1v2 v3 v4v5 v6v

20 Grafos - 20 Estádios do algoritmo de Dijkstra v1v2 v3 v4v5 v6v v1v2 v3 v4v5 v6v v1v2 v3 v4v5 v6v v1v2 v3 v4v5 v6v

21 Grafos - 21 Evolução da estrutura de dados v v v v 1 0 2v 1 1 2v 1 v v 4 0 3v 4 v v 1 1 1v 1 1 1v 1 v v 4 03v 4 v v 4 09v 4 v v 4 Início Visita v 1 Visita v 4 Visita v 2 knownd v p v

22 Grafos - 22 Evolução da estrutura de dados v v v 2 1 2v 1 12v 1 1 2v 1 1 2v 1 v 3 0 3v 4 1 3v 4 1 3v 4 1 3v 4 v 4 1 1v 1 11v 1 1 1v 1 1 1v 1 v 5 13v 4 13v 4 13v 4 13v 4 v 6 09v 4 08v 3 06v 7 16v 7 v 7 05v 4 05v 4 15v 4 15v 4 Visita v 3 Visita v 7 Visita v 6 knownd v p v Visita v 5

23 Grafos - 23 Algoritmo de Dijkstra void Dijkstra( Vertex s) { Vertex v, w; s.dist = 0; for( ; ; ) { v = vertice_a_menor_distancia; if( v == null ) break; v.known = true; for each w adjacent to v if( !w.known ) if v.dist + c(v,w) < w.dist ) { w.dist = v.dist + c(v,w); w.path = v; } }}

24 Grafos - 24 Análise do algoritmo oproblema: pesquisa do mínimo método de percorrer a tabela até encontrar o mínimo é O(|V|) em cada fase; gasta- se O(|V| 2 ) tempo ao longo do processo tempo de corrigir a distância é constante por actualização e há no máximo uma por aresta, num total de O(|E|) tempo de execução fica O(|E| + |V| 2 ) = O(|V| 2 ) se o grafo for denso |E| = (|V| 2 ) e o resultado é satisfatório pois corre em tempo linear no número de arestas se o grafo fôr esparso |E| = (|V|), o algoritmo é demasiado lento omelhoria: manter as distâncias numa fila de prioridade para obter o mínimo eficientemente O(log |V|), com uma operação deleteMin como as distâncias vão sendo alteradas no processo e a operação de Busca é ineficiente nas filas de prioridade, pode-se meter na fila mais do que um elemento para o mesmo vértice, com distâncias diferentes, e ter o cuidado, ao apagar o mínimo, de verificar se o vértice já está processado O(|E| log |V|) actualização dos pesos com operação decreaseKey na fila O(|V| log |V|) percorrer os vértices com operação deleteMin para cada Tempo de execução total: O(|E| log |V|)

25 Grafos Arestas com custos negativos oAlgoritmo de Dijkstra não funciona custo ao longo de um caminho não é monótono depois de se marcar um vértice como processado pode aparecer um caminho mais longo mas com custo inferior oCombinar os algoritmos para os caminhos pesado e sem peso usar uma fila; colocar o vértice inicial em cada passo -retirar um vértice v da fila -para cada vértice w adjacente a v tal que dist(w) dist(v) + cost(v, w) actualizar dist(w), path(w) e colocar w na fila, se lá não estiver -manter uma indicação de presença na fila

26 Grafos - 26 Exemplo: custos negativos     Achar os caminhos de menor custo a começar em 1. Dijkstra vértice 2 não altera nada … seria necessário rever 4 e propagar as alterações; piora o tempo … pretendido:

27 Grafos - 27 Algoritmo com custo negativo pode ser necessário processar cada vértice mais do que uma vez (max: |V|) actualização pode ser executada O(|E|.|V|), usando listas de adjacência void weightedNegative( Vertex s) { Vertex v, w; Queue q; q = new Queue(); q.enqueue (s); while( !q.isEmpty() ) { v = q.dequeue(); for each w adjacent to v if v.dist + c(v,w) < w.dist ) { w.dist = v.dist + c(v,w); w.path = v; if(w not in q) ) q.enqueue(w); } ciclo de custo negativo algoritmo não termina teste de terminação: algum vértice sai da fila mais do que |V|+1 vezes

28 Grafos Grafos acíclicos osimplificação do algoritmo de Dijkstra exigência de selecção, em cada passo, do vértice mínimo é dispensável nova regra de selecção: usar a ordem topológica um vértice processado jamais pode vir a ser alterado: não há ramos a entrar não é necessária a fila de prioridade ordenação topológica e actualização das distâncias combinadas numa só passagem oaplicações em processos não reversíveis não se pode regressar a um estado passado (certas reacções químicas) deslocação entre dois pontos em esqui (sempre descendente) oaplicações de Investigação Operacional modelar sequências de actividades em projectos grafos nó-actividade - nós representam actividades e respectiva duração - arcos representam precedência (um arco de v para w significa que a actividade em w só pode ser iniciada após a conclusão da de v) acíclico

29 Grafos - 29 Grafos Nó-Actividade Qual a duração total mínima do projecto? Quais as actividades que podem ser atrasadas e por quanto tempo (sem aumentar a duração do projecto)? A(3) D(2) E(1) C(3) B(2) F(3) G(2) K(4) H(1) iníciofim Nó: actividade e tempo associado Arco: precedência

30 Grafos - 30 Reformulação em Grafo Nó-Evento nó = evento arco = actividade evento: fim de actividade reformulação introduz nós e arcos extra para garantir precedências A/3 B/2 C/3 E/1 D/ F/3 G/ H/1 Nó: evento- completar actividade Arco: actividade K/4

31 Grafos - 31 Menor Tempo de Conclusão menor tempo de conclusão caminho mais comprido do evento inicial ao nó problema (se grafo não fosse acíclico): ciclos de custo positivo adaptar algoritmo de caminho mais curto MTC(1) = 0 MTC(w) = max( MTC(v) + c(v,w) ) (v, w) E A/3 B/2 C/3 E/1 D/ F/3 G/ H/1 MTC : usar ordem topológica K/4 3

32 Grafos - 32 Último Tempo de Conclusão último tempo de conclusão: mais tarde que uma actividade pode terminar sem comprometer as que se lhe seguem UTC(n) = MTC(n) UTC(v) = min( UTC(w) - c(v w) ) (v, w) E UTC : usar ordem topológica inversa A/3 B/2 C/3 E/1 D/ F/3 G/ H/ K/ valores calculados em tempo linear mantendo listas de adjacentes e de precedentes dos nós

33 Grafos - 33 Folgas nas actividades folga da actividade folga(v,w) = UTC(w)-MTC(v)-c(v,w) A/3/0 B/2/2 C/3/0 E/1/2 D/2/1 F/3/0 G/2/2 H/1/ K/4/ Caminho crítico: só actividades de folga nula (há pelo menos 1)

34 Grafos - 34 Problemas de fluxo numa rede Modelar fluxos conservativos entre dois pontos através de canais com capacidade limitada 1Fluxo num arco não pode ultrapassar a capacidade 2Soma das entradas num nó igual à soma das saídas Exemplos abastecimento de líquido ponto a ponto tráfego entre dois pontos - s: fonte; t: poço - distribuição de fluxo pelos arcos arbitrária, desde que respeite as setas ab dc s t ab dc s t

35 Grafos - 35 Fluxo máximo: 1ª abordagem oalgoritmo simples de aproximações sucessivas baseado em G ä grafo base de capacidades Gf ä grafo auxiliar de fluxos - inicialmente fluxos iguais a 0 - no fim, fluxo máximo Gr ä grafo residual (auxiliar) - capacidade disponível em cada arco (= capacidade - fluxo) - capacidade disponível = 0 eliminar arco saturado ométodo de calcular o fluxo máximo entre s e t em cada iteração, selecciona-se um caminho em Gr entre s e t (de acréscimo) algoritmo não determinístico valor mínimo nos arcos desse caminho = quantidade a aumentar a cada um dos arcos respectivos em Gf recalcular Gr termina quando não houver caminho de s para t

36 Grafos - 36 Exemplo: estado inicial ab dc s t ab dc s t ab dc s t GGfGf GrGr

37 Grafos - 37 Exemplo: 1ª iteração ab dc s t ab dc s t ab dc s t GGfGf GrGr

38 Grafos - 38 Exemplo: 2ª iteração ab dc s t ab dc s t ab dc s t GGfGf GrGr

39 Grafos - 39 Exemplo: 3ª iteração ab dc s t ab dc s t ab dc s t GGfGf GrGr

40 Grafos - 40 Algoritmo não garante fluxo óptimo ocritério ganancioso de selecção do caminho: escolher o que dê maior fluxo - caminho s, a, d, t (3 unidades de fluxo) ä algoritmo termina sem obter o máximo - exemplo de algoritmo ganancioso que falha ab dc s t ab dc s t ab dc s t

41 Grafos - 41 Algoritmo determinístico permitir que o algoritmo mude de ideias para cada arco (v,w) com fluxo f(v,w) no grafo de fluxos acrescenta-se um arco (w,v) no grafo residual com capacidade f(v,w) - corresponde a deixar devolver fluxo para trás (nunca fica globalmente negativo, contra o arco) - podem existir arcos em sentidos opostos; podem existir ciclos se as capacidades forem números racionais, o algoritmo termina com máximo se as capacidades forem inteiros e o fluxo máximo f - bastam f estádios (fluxo aumenta pelo menos 1 por estádio) - tempo de execução ( caminho mais curto não pesado ) é O(f. |E| ) ä mau evitar o problema - escolher caminho que dá maior aumento de fluxo - semelhante ao problema do caminho pesado mais curto (pequena alteração a Dijkstra) - fluxo máximo em O(|E| log capMax) (capMax = capacidade máxima de um arco) - cada cálculo de um aumento em O(|E| log |V|) (Dijkstra) - global: O(|E|^2 log |V| log capMax)

42 Grafos - 42 Solução óptima - 1ª iteração ab dc s t ab dc s t ab dc s t GGfGf GrGr 3 3 unidades de fluxo no caminho sadt

43 Grafos - 43 Solução óptima - 2ª iteração ab dc s t ab dc s t ab dc s t GGfGf GrGr unidades de fluxo no caminho s,b,d,a,c, t

44 Grafos - 44 Caso difícil s a b t s a b t s a b t s a b t s a b t se se escolher passar sempre por a e por b… … temos de iterações, em vez de 2!

45 Grafos - 45 Árvores de expansão mínimas Árvore que liga todos os vértices do grafo usando arestas com um custo total mínimo caso do grafo não dirigido grafo tem que ser conexo árvore acíclico número de arestas = |V| - 1 oexemplo de aplicação: cablamento de uma casa - vértices são as tomadas - arestas são os comprimentos dos troços

46 Grafos - 46 Algoritmo de Prim oexpandir a árvore por adição sucessiva de arestas e respectivos vértices critério de selecção: escolher a aresta (u,v) de menor custo tal que u já pertence à árvore e v não (ganancioso) início: um vértice qualquer oidêntico ao algoritmo de Dijkstra para o caminho mais curto informação para cada vértice - dist(v) é o custo mínimo das arestas que ligam a um vértice já na árvore - path(v) é o último vértice a alterar dist(v) - known(v) indica se o vértice jé foi processado (isto é, se já pertence à árvore) diferença na regra de actualização: após a selecção do vértice v, para cada w não processado, adjacente a v, dist(w) = min{ dist(w), cost(w,v) } tempo de execução - O( |V| 2 ) sem fila de prioridade - O( |E| log |V| ) com fila de prioridade

47 Grafos - 47 Evolução do algoritmo de Prim ¶ · ¸ ¹ º » ¼ vknowndistpath última tabela

48 Grafos - 48 Algoritmo de Kruskal oanalisar as arestas por ordem crescente de peso e aceitar as que não provocarem ciclos (ganancioso) ométodo manter uma floresta, inicialmente com um vértice em cada árvore (há |V|) adicionar uma aresta é fundir duas árvores quando o algoritmo termina há só uma árvore (de expansão mínima) oanalisar as arestas por ordem crescente de peso e aceitar as que não provocarem ciclos (ganancioso) ométodo manter uma floresta, inicialmente com um vértice em cada árvore (há |V|) adicionar uma aresta é fundir duas árvores quando o algoritmo termina há só uma árvore (de expansão mínima) oaceitação de arestas algoritmo de Busca/União em conjuntos representados como árvores se dois vértices pertencem à mesma árvore/conjunto, mais uma aresta entre eles provoca um ciclo (2 Buscas) se são de conjuntos disjuntos, aceitar a aresta é aplicar-lhes uma União oselecção de arestas: ordenar por peso ou, melhor, construir fila de prioridade em tempo linear e usar Apaga_Min tempo no pior caso O( |E| log |E| ), dominado pelas operações na fila

49 Grafos - 49 Pseudocódigo (Kruskal) void kruskal() { DisjSet s; PriorityQueue h; Vertex u, v; SetType uset, vset; Edge e, int edgesAccepted = 0; h = readGraphIntoHeapArray(); h.buildHeap(); s = new DisjSet(NUM_VERTICES); while(edgesAccepted < NUM_VERTICES -1 ) { e = h.deleteMin();// e = (u,v) uset = s.find(u); vset = s.find(v); if (uset != vset) { edgesAccepted++; S.union(uset, vset); } }}

50 Grafos - 50 Evolução do algoritmo de Kruskal ¶ ·¸

51 Grafos - 51 Evolução do algoritmo de Kruskal ¹ º » ¼

52 Grafos - 52 Pesquisa em profundidade void 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 ogeneralizaçã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

53 Grafos Grafos não dirigidos A B C D E A B C D E um grafo não dirigido é conexo uma pesquisa em profundidade a começar em qualquer nó visita todos os nós ocomeç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) oárvore simula a pesquisa; numeração em pré-ordem pelas arestas da árvore dá a ordem de marcação dos vértices grafo árvore de expansão em profundidade

54 Grafos Biconectividade Grafo conexo não dirigido é biconexo se não existe nenhum vértice cuja remoção torne o resto do grafo desconexo Grafo conexo não dirigido é biconexo se não existe nenhum vértice cuja remoção torne o resto do grafo desconexo oAplicação - rede com tolerância a falhas oPontos de articulação - vértices que tornam o grafo desconexo (críticos) oAlgoritmo 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)

55 Grafos - 55 Pontos de articulação oCá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| ) oVértice v é ponto de articulação se tiver um filho w tal que Low(w) Num(v) oA raiz é ponto de articulação sse tiver mais que um filho na árvore oLow(v) é mínimo de Num(v) o menor Num(w) de todas as arestas (v,w) de retorno o menor Low(w) de todos as arestas (v,w) da árvore

56 Grafos - 56 Detecção de pontos de articulação Pontos de articulação: C e D A B C D F A,1/1 B,2/1 C,3/1 D,4/1 G,7/7 grafoárvores de expansão em profundidade E G E,5/4 F,6/4 A,5/1 B,6/1 C,1/1 D,2/1 G,7/7 E,3/2 F,4/2 v, Num(v)/Low(v)

57 Grafos - 57 Três passagens? Num(v) pre-ordem Low(v) pos-ordem pontos de articulação pos-ordem combinados // Atribui numero e calcula pai // Contador global e inicializado a 1 void assignNum( Vertex v) { v.num = counter++; v.visited = true; for each w adjacent to v if( !w.visited ) { w.parent = v; assignNum(w); } // Atribui Low // Testa Pontos de Articulação void assignLow( Vertex v) { v.low = v.num;// regra 1 for each w adjacent to v if(w.num > v.num) // ramo árvore { assignLow(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 ) // retorno v.low = min(v.low, w.num); // regra 2 }

58 Grafos - 58 Uma só pesquisa em profundidade Combina o pré-processamento e o pós-processamento numa única passagem // Procura Pontos de Articulação // 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 á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 )// retorno v.low = min(v.low, w.num); // regra 2 }

59 Grafos 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

60 Grafos - 60 Solução ocondiçã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 ocondição suficiente se se verificarem as condições acima, então existe circuito (caminho) de Euler omé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) oCiclo Hamiltoniano: ciclo simples que visita todos os vértices? (vê-se depois)

61 Grafos - 61 Exemplo de um circuito Grafo: existe caminho de Euler Depois de fazer caminho 5, 4, 10, 5

62 Grafos - 62 Exemplo de um circuito Depois de fazer caminho 5, 4, 1,3,7,4,11,10,7,9,3,4,10, Depois de fazer caminho 5, 4, 1, 3, 2, 8, 9, 6, 3, 7, 4, 11, 10, 7, 9, 3, 4, 10, 5

63 Grafos Grafos dirigidos o(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…) AB DC E F G H JI

64 Grafos - 64 Árvore de expansão opesquisa em profundidade induz uma árvore/floresta de expansão opara 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 A B CF D E H J I G

65 Grafos - 65 Componentes fortemente conexos oMétodo: pesquisa em profundidade no grafo G determina floresta de expansão, numerando vértices em pós-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 ocada árvore obtida é um componente fortemente conexo, i.e., a partir de um qualquer dos nós pode chegar-se a todos os outros oProva 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.

66 Grafos - 66 Componentes fortemente conexos A,3B,6 D,2C,4 E,1 F,5 G,10 H,9 J,8I,7 G r : obtido de G por inversão de todas as arestas Numeração: da travessia de G em pós-ordem

67 Grafos - 67 Componentes fortemente conexos A B C F DEH J I G Travessia em pós-ordem de G r Componentes fortemente conexos: {G}, {H, I, J}, {B, A, C, F}, {D}, {E}


Carregar ppt "Grafos - 1 Grafos oGrafo G = (V, E) V conjunto de vértices E conjunto de arestas (ou arcos) - cada aresta é um par de vértices (v, w), em que v, w V -"

Apresentações semelhantes


Anúncios Google