Noções de Grafos #2

Birds

 

A representação de grafos em um computador é uma questão importante a ser pensada quando estamos modelando um problema que necessita dessa estrutura. Existem duas abordagens muito populares utilizadas para representar um grafo computacionalmente. Sendo elas: matriz de adjacências e lista de adjacências. Veremos nesse artigo o que elas são e como funcionam, além disso, será explorado os diversos tipos de grafos mais utilizados.

 

Matriz de adjacência

A representação de um grafo, sendo ela por matriz ou por lista de adjacência varia muito de problema para problema. Não existe uma representação certa ou errada, mas existe a representação ideal que melhor se adequa para o problema em questão.

Uma matriz de adjacência faz o uso de uma matriz quadrada para descrever as relações entre os vértices. Nessa representação, um grafo contendo N vértices utiliza uma matriz de N linhas e N colunas para seu armazenamento. Em relação ás arestas, é atribuido o número 1 caso a aresta existe e 0 caso contrário.

Essa representação não é indicada para um grafo que possui muitos vértices, mas poucas arestas ligando-os.

Uma aresta é representada por uma marca na posição [i,j] da matriz.

https://imgur.com/b0LMuFf.png

 

Lista de adjacência

Existe um problema de eficiência quanto o armazenamento do grafo na matriz de adjacência, este problema se deve ao fato de, além de haver a necessidade de um alto custo computacional O(n), a matriz armazenar o valor 0 caso não exista uma aresta. A representação por lista de adjacência resolve este problema, sendo assim, ela armazena só os vértices que possuem arestas ligando-os. Essa representação faz o uso de uma estrutura de lista de vértices para descrever suas relações.

Um grafo contendo N vértices utiliza um array de ponteiros de tamanho N para armazenar os vértices do grafo. Em seguida, para cada vértice é criada uma lista de arestas, em que cada posição da lista armazena o índice do vértice e as quais vértices ele se conecta.

A lista de adjacência é mais indicada para um grafo que possui muitos vértices, mas poucas arestas ligando-os.

Essa representação possui um custo computacional de O(N+M), onde N é o número de vértices e M é o número de arestas.

Além disso, para saber se dois vértices estão conectados é necessário percorrer todas as arestas de um deles, enquanto na matriz de adjacência essa operação é realizada de forma imediata.

https://imgur.com/OTroIkj.png

 

Tipos de grafos

Trivial e simples

Um grafo trivial possui um único vértice e nenhuma aresta. Já um grafo simples é um grafo não direcionado, sem laços e sem arestas paralelas.

https://imgur.com/JyfUSgv.png

 

Completo

É um grafo simples onde cada vértice se conecta a todos os outros vértices do grafo.

https://imgur.com/enNNffm.png

 

Regular

Qualquer grafo cujos vértices possuem o mesmo grau.

TOdo grafo completo também é regular, mas nem todo grafo regular é completo.

https://imgur.com/YQCFL7C.png

 

Subgrafo

Um grafo G′=(V′, A′) é um subgrafo de G=(V,A) se V′ for um subconjunto de V e, para cada par de vertices (x,y) em V′, (x,y) são adjacentes em G′ se, e somente se, eles sao adjacentes em G.

Em outras palavras, G’=(V’,A’) é um subgrafo de G=(V,A) se o conjunto de vértices V’ for um subconjunto de V, onde V’ está contido em V, e se o conjunto de arestas A’ for um subconjunto de A, onde A’ está contido em A.

https://imgur.com/Sj6dfRw.png

 

Bipartido

Um grafo G(V,A) é chamado de bipartido se o seu conjunto de vértices puder ser dividido em dois outros subconjuntos ‘V1’ e ‘V2’ sem intersecção. Já as arestas conectam apenas os vértices que estão em subconjuntos diferentes, ou seja, uma aresta sempre conecta um vértice de ‘V1’ a ‘V2’ ou vice-versa, porém ela nunca conecta vértices do mesmo subconjunto entre si.

Todo ciclo tem comprimento par em um grafo bipartido;

Para checar que um grafo é bipartido basta checar se ele possui ao menos um ciclo de comprimento ímpar.

https://imgur.com/qg7Jvar.png

 

Conexo e desconexo

Um grafo conexo possui um caminho ligando quaisquer dois vértices, ou seja, para quais quer dois vértices distintos sempre existe um caminho que os une. Em contrapartida, em um grafo desconexo isso não acontece. Um grafo desconexo contém no mínimo duas partes, cada uma delas chamada de componente conexa.

https://imgur.com/KUCTCIa.png

 

Isomorfo

Dois grafos são ditos isomorfos se existir uma função que faça o mapeamento dos vértices e arestas de modo que os dois grafos se tornem correspondentes. Resumidamente, dois grafos são isomorfos se houver uma função f tal que, para cada dois vértices a e b adjacentes em um grafo G1, f(a) e f(b) também sejam adjacentes em um grafo G2.

Existem algumas condições mínimas para que dois grafos sejam isomorfos. São elas:

https://imgur.com/bxKcRZt.png

 

Ponderado

As arestas possuem valores (pesos) associados a elas. Esse tipo de grafo e largamente usado nas engenharias para representação de grandezas, altitudes, distâncias, capacidades ou fluxos.

https://imgur.com/c6PY6nz.png

 

Euleriano

Um grafo euleriano é um tipo especial de grafo que possui um ciclo que visita as suas arestas apenas uma vez, iniciando e terminando no mesmo vertice. Esse ciclo dá-se o nome de ciclo euleriano.

https://imgur.com/bmuDnDi.png

 

Semieuleriano

Um grafo semieuleriano possui um caminho aberto, cujo não é um ciclo, em que visita todas as suas arestas apenas uma vez. Dá-se o nome de caminho euleriano para esse caminho.

https://imgur.com/yxIzfMV.png

 

Hamiltoniano

Um grafo é dito hamiltoniano quando possui um caminho que visita todos os seus vértices apenas uma vez.

O problema de verificar se existe um caminho (ou ciclo) hamiltoniano em um grafo é NP-completo, ou seja, é pouco provável que exista um algoritmo polinomial para resolver isso.

https://imgur.com/ktlWStV.png

 

Planar

Todo grafo que pode ser desenhado no plano, com pontos representando vertices e linhas contınuas conectando pares de pontos representando arestas, sem que haja duas arestas se intersectando.

 

Árvore

Uma árvore é um grafo acíclico, não orientado e conexo. A diferença de uma árvore para uma floresta (conjunto de árvores e sub-árvores) é que em uma floresta existe a possibilidade do grafo ser desconexo.

Toda árvore é um grafo mas nem todo grafo é uma árvore.

https://imgur.com/mCJ0aay.png

 

Conectividade em Grafos

Componente conexa

Um grafo G=(V,A) desconexo é formado por pelo menos dois subgrafos conexos, disjuntos em relação aos vértices. Assim, cada um deste subgrafos conexos é dito ser uma componente conexa de G.

https://imgur.com/2A2aJ67.png

 

Vértice de corte

Um vértice é dito ser um vértice de corte se sua remoção (juntamente com as arestas a ele conectadas) produz um grafo com mais componentes conexos.

Se o grafo original é conexo, ele se torna desconexo

https://imgur.com/EnXaXps.png

No grafo acima, o vértice de corte é o de valor 2.

 

Ponte

Uma aresta é dita ser uma ponte se sua remoção produz um grafo com mais componentes conexos.

https://imgur.com/8nzdXV2.png

 

Conclusão

Neste artigo exploramos os principais tipos de grafos utilizados, como o trivial, simples, completo, regular, subgrafo e bipartido. Além disso, vimos como representar a estrutura de um grafo na máquina e a relação dos grafos com sua conectividade. A compreensão desses conceitos é fundamental para a solução de problemas que envolvem grafos e para a compreensão dos próximos artigos que virão em sequência.

 

Referências

DFS and BFS algorithms

Estrutura de Dados Descomplicada - Em Linguagem C , por André Backes


Obrigado pela leitura!