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

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

Grafos Grafo G = (V, E) V — conjunto de vértices

Apresentações semelhantes


Apresentação em tema: "Grafos Grafo G = (V, E) V — conjunto de vértices"— Transcrição da apresentação:

1 Grafos Grafo 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 1 2 1 2 3 4 5 3 4 5 6 7 6 7 G1= (Cruzamentos, Ruas) G2 = (Cidades, Estradas)

2 Mais definições caminho — sequência de vértices v1, v2, …, vn tais que (vi, vi+1) Î E, 1 i <n comprimento do caminho é o número de arestas, n-1 - se n = 1, o caminho reduz-se a um vértice v1; comprimento = 0 anel — caminho v, v Þ (v, v) Î E , comprimento 1; raro caminho simples — todos os vértices distintos excepto possivelmente o primeiro e o último ciclo — caminho de comprimento  1 com v1 = vn num grafo não dirigido requer-se que as arestas sejam diferentes DAG — grafo dirigido acíclico conectividade grafo não dirigido é conexo sse houver um caminho a ligar qualquer par de vértices digrafo com a mesma propriedade — fortemente conexo digrafo fracamente conexo — não fortemente conexo; grafo subjacente conexo densidade grafo completo — existe uma aresta entre qualquer par de nós grafo denso — |E| = Q(V2) grafo esparso — |E| = Q(V)

3 Representação matriz de adjacências 1 2 3 4 5 6 7 0 1 1 1 0 0 0
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 Lista de adjacências estrutura 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 grafo não dirigido: matriz simétrica; lista com o dobro do espaço 1 2 4 3 2 4 5 3 6 4 6 7 3 5 4 7 6 7 6

5 Ordenação topológica 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 impossível se o grafo for cíclico não é necessariamente única ( ) ou ( ) no exemplo anterior algoritmo 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 )

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 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 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 Execução no grafo de exemplo
indegree anterior a cada operação dequeue Vértice v v v v v v v enqueue v1 v2 v5 v4 v3,v7 v6 dequeue v1 v2 v5 v4 v3 v7 v6

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 Exemplo: 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 …) Outro 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 1 2 3 4 5 6 7 -10

11 1 - Caminho não pesado pretende-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 este tipo de pesquisa em grafos designa-se por pesquisa em largura semelhante à travessia por níveis de uma árvore có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 Evolução da marcação do grafo
1 v1 v2 v3 v4 v5 v6 v7 v1 v2 v3 v4 v5 v6 v7 1 1 1 2 2 v1 v2 v3 v4 v5 v6 v7 v1 v2 v3 v4 v5 v6 v7 2 2 3 3 1 1

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 Eficiência do algoritmo básico
tempo de execução O(|V|^2), devido aos ciclos for encaixados remoçã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 Algoritmo refinado 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 ); } }} tempo de execução é O(|E| + |V|), com grafo representado por lista de adjacências

16 Evolução da estrutura de dados
Início Visita v3 Visita v1 Visita v6 v known dv pv known dv pv known dv pv known dv pv v1 0  v v v3 v2 0  0 0  v v1 v v4 0  0 0  v v1 v5 0  0 0  0 0  0 0  0 v6 0  v v v3 v7 0  0 0  0 0  0 0  0 Q v3 v1, v6 v6, v2, v4 v2, v4

17 Evolução da estrutura de dados
Visita v2 Visita v4 Visita v5 Visita v7 v Known dv pv Known dv pv Known dv pv Known dv pv v1 1 1 v v v v3 v v v v v1 v v v v v v1 v v v v v2 v6 1 1 v v v v3 v7 0  v v v4 Q v4, v5 v5, v7 v7 (vazia)

18 2 - Caminho pesado a 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 este é um exemplo de um algoritmo ganancioso: em cada passo faz o que melhora o ganho imediato restrição: só é válido se não existirem custos negativos regista-se o vértice antecedente, responsável directo pelo custo estimado; seguindo a sequência recupera-se o caminho mínimo

19 Estádios do algoritmo de Dijkstra
v1 v2 v3 v4 v5 v6 v7 4 2 10 6 1 5 3 8 v1 v2 v3 v4 v5 v6 v7 4 2 10 6 1 5 3 8 v1 v2 v3 v4 v5 v6 v7 4 2 10 6 1 5 3 8 v1 v2 v3 v4 v5 v6 v7 4 2 10 6 1 5 3 8

20 Estádios do algoritmo de Dijkstra
v1 v2 v3 v4 v5 v6 v7 4 2 10 6 1 5 3 8 v1 v2 v3 v4 v5 v6 v7 4 2 10 6 1 5 3 8 v1 v2 v3 v4 v5 v6 v7 4 2 10 6 1 5 3 8 2 v1 v2 4 1 10 3 v3 2 v4 v5 2 8 4 5 6 v6 v7 1

21 Evolução da estrutura de dados
Início Visita v1 Visita v4 Visita v2 v known dv pv known dv pv known dv pv known dv pv v v2 0  v v v1 v3 0  0 0  v v4 v4 0  v v v1 v5 0  0 0  v v4 v6 0  0 0  v v4 v7 0  0 0  0 0  v4

22 Evolução da estrutura de dados
Visita v5 Visita v3 Visita v7 Visita v6 v known dv pv known dv pv known dv pv known dv pv v v v v v v1 v v v v v4 v v v v v1 v5 1 3 v v v v4 v6 0 9 v v v v7 v7 0 5 v v v v4

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 Análise do algoritmo problema: 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| = Q(|V|2) e o resultado é satisfatório pois corre em tempo linear no número de arestas se o grafo fôr esparso |E| = Q(|V|), o algoritmo é demasiado lento melhoria: 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 3 - Arestas com custos negativos
Algoritmo 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 Combinar 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 Exemplo: custos negativos
Achar os caminhos de menor custo a começar em 1. 2 1 2 4 1 10 -2 3 2 2 4 5 8 4 5 6 6 1 7 Dijkstra 2 2 vértice 2 não altera nada … 2 2 1 2 1 2 4 4 1 10 1 10 -2 -2 1 1 3 2 2 5 3 3 2 2 4 5 3 4 8 8 4 4 5 5 6 6 6 1 6 1 7 7 2 9 5 2 1 2 4 1 10 -2 seria necessário rever 4 e propagar as alterações; piora o tempo … pretendido: 3 2 2 2 4 5 2 8 4 5 6 6 1 7 8 4

27 Algoritmo com custo negativo
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); } 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 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 4 - Grafos acíclicos simplificaçã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 aplicaçõ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) aplicaçõ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 Nó-Actividade Nó: actividade e tempo associado
Arco: precedência C(3) A(3) F(3) início D(2) H(1) fim B(2) G(2) K(4) E(1) 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)?

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

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 MTC : usar ordem topológica 3 6 C/3 2 4 A/3 6 9 F/3 7’ 7 3 5 9 10 D/2 H/1 1 6’ 6 10’ 10 5 7 G/2 8’ 8 7 B/2 2 3 E/1 K/4 9 3 5

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 valores calculados em tempo linear mantendo listas de adjacentes e de precedentes dos nós 3 6 C/3 2 4 A/3 6 9 3 6 F/3 7’ 7 3 5 9 10 D/2 6 H/1 1 6’ 6 9 10’ 10 5 7 G/2 4 6 8’ 8 9 10 7 B/2 2 3 E/1 7 K/4 9 9 3 5 9 4 5

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

34 Problemas de fluxo numa rede
Modelar fluxos conservativos entre dois pontos através de canais com capacidade limitada s s Fluxo num arco não pode ultrapassar a capacidade Soma das entradas num nó igual à soma das saídas 3 2 3 2 1 a b a b 4 1 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 3 2 2 2 c d c d 2 3 2 3 t t

35 Fluxo máximo: 1ª abordagem
algoritmo 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 mé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 Exemplo: estado inicial
3 2 3 2 1 1 a b a b a b 4 4 3 2 3 2 c d c d c d 2 3 2 3 t t t G Gf Gr

37 Exemplo: 1ª iteração s s s a b a b a b c d c d c d t t t G Gf Gr 3 2 2
2 3 1 1 a b a b a b 4 4 3 2 2 3 c d c d c d 2 3 2 2 1 t t t G Gf Gr

38 Exemplo: 2ª iteração s s s a b a b a b c d c d c d t t t G Gf Gr 3 2 2
1 1 1 a b a b a b 4 4 3 2 2 2 1 c d c d c d 2 3 2 2 1 t t t G Gf Gr

39 Exemplo: 3ª iteração s s s a b a b a b c d c d c d t t t G Gf Gr 3 2 3
1 1 a b a b a b 4 1 3 3 2 2 2 1 c d c d c d 2 3 2 3 t t t G Gf Gr

40 Algoritmo não garante fluxo óptimo
crité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 s s s 3 2 3 2 1 1 a b a b a b 4 3 1 3 2 3 2 c d c d c d 2 3 3 2 t t t

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 Solução óptima - 1ª iteração
3 2 3 3 2 1 1 a b a b a b 4 3 1 3 2 3 2 3 c d c d c d 2 3 3 2 3 t t t G Gf Gr 3 unidades de fluxo no caminho sadt

43 Solução óptima - 2ª iteração
3 2 3 2 3 2 1 1 a b a b a b 4 1 3 3 2 2 2 2 3 2 1 c d c d c d 2 3 2 3 2 3 t t t G Gf Gr 2 unidades de fluxo no caminho s,b,d,a,c, t

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

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 exemplo de aplicação: cablamento de uma casa - vértices são as tomadas - arestas são os comprimentos dos troços

46 Algoritmo de Prim expandir 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 idê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 Evolução do algoritmo de Prim
última tabela known dist path 1 0 0 1 2 1 1 2 4 1 1 1 1 6 7 1 1 7 1 4 4 2 1 2 4 10 1 3 3 2 7 4 5 8 4 5 6 6 1 7 2 1 1 1 2 2 1 2 1 1 4 4 3 2 4 2 2 2 1 2 1 2 1 2 1 1 1 3 2 4 3 2 4 3 2 4 5 4 4 4 6 7 6 1 7 6 1 7

48 Algoritmo de Kruskal analisar as arestas por ordem crescente de peso e aceitar as que não provocarem ciclos (ganancioso) mé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) aceitaçã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 selecçã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 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 Evolução do algoritmo de Kruskal
1 2 3 4 5 6 7 10 8 1 2 3 4 5 6 7 1 2 1 2 1 1 3 5 3 4 5 4 6 1 6 7 7

51 Evolução do algoritmo de Kruskal
1 2 3 4 5 6 7 10 8 2 1 2 1 3 4 5 6 1 7 2 2 1 2 1 2 1 1 5 3 2 4 5 3 2 4 4 6 1 7 6 1 2 7 1 2 1 3 2 4 5 4 6 6 1 7

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

53 1 - Grafos não dirigidos A A B B D E C 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

54 2 - Biconectividade Grafo 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)

55 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 todos 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

56 Detecção de pontos de articulação
grafo á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) F,6/4 E,5/4 Pontos de articulação: C e D

57 Três passagens? • Num(v) — pre-ordem • Low(v) — pos-ordem
// 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 • Num(v) — pre-ordem • Low(v) — pos-ordem • pontos de articulação — pos-ordem combinados

58 Uma só pesquisa em profundidade
// 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 Combina o pré-processamento e o pós-processamento numa única passagem

59 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

60 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)

61 Exemplo de um circuito Grafo: existe caminho de Euler
1 2 3 4 5 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

62 Exemplo de um circuito Depois de fazer caminho
1 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

63 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

64 Árvore de expansão B H G C F A J D I E
pesquisa 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

65 Componentes fortemente conexos
Mé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 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.

66 Componentes fortemente conexos
A,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

67 Componentes fortemente conexos
G 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}


Carregar ppt "Grafos Grafo G = (V, E) V — conjunto de vértices"

Apresentações semelhantes


Anúncios Google