Algoritmos Computacionais

Artigos sobre lógica de programação por Tiago Madeira

algoritmo: do Lat. algorithmos < Ár. alkharizmi: [Inform.] conjunto de etapas bem definidas necessárias para chegar à resolução de um problema.

Archive for the 'Grafos' Category

Grafos Ponderados

Thursday, January 26th, 2006

Um grafo é ponderado quando suas arestas possuem um peso. O que significa isso? Bom... Vamos supor que eu queira ir de um lugar pra outro, mas o mais importante pra mim não seja a distância entre eles mas o pedágio que vou ter que pagar para pegar cada aresta (estrada). Nesse caso, o peso de cada aresta seria o custo que eu tenho pra passar pela estrada. O problema então seria calcular o caminho onde eu pago menos (o caminho que tem a menor soma de preços) e não o menor caminho no grafo "não-ponderado" (onde consideramos aresta=1 e nada=0).

Grafo Ponderado

Neste grafo, por exemplo, o menor caminho de 1 a 3 não é a aresta 1-3, mas sim a aresta 1-2 e depois a aresta 2-3.

Para representar um grafo ponderado, precisamos usar a matriz de adjacência, porque na lista de adjacência não temos como registrar o peso de cada aresta. Onde antes marcávamos "1", marcamos o peso que temos de ir de um vértice para o outro e onde marcávamos "0" marcamos LaTeX: \infty{} (infinito)*.

  1 2 3 4
1 LaTeX: \infty{} 10 40 LaTeX: \infty{}
2 10 LaTeX: \infty{} 20 50
3 40 20 LaTeX: \infty{} 20
4 LaTeX: \infty{} 50 20 LaTeX: \infty{}

* Na verdade, só fazemos isso porque neste caso queremos o menor caminho e o 0 poderia atrapalhar, porque poderíamos ter um caminho sem pedágio, por exemplo.

E grafos ponderados são isso. Não tem segredo. Na representação comum de grafos, você coloca o peso em cima ou do lado da aresta e pra representar na matriz de adjacências coloca o peso na posição matriz[v][w] (v e w são sempre vértices... v=vértice, w=próxima letra depois do v :) )

Mini-artigo... Ainda não entramos nos algoritmos e ainda não vamos entrar. Isso vai ficar pro próximo artigo: Busca em Profundidade. Espero que tenham gostado e qualquer coisa postem um comentário.

Compare Preços de: notebooks, acer aspire, hp pavilion, computadores, pentium 4, nintendo wii, ps3, celulares, câmeras digitais

Representando Grafos na Programação

Monday, January 23rd, 2006

No último artigo, conhecemos a representação chamada "grafo" da seguinte maneira:

Exemplo 1

Como todos sabemos, seria bem difícil trabalhar uma árvore assim na programação! :D Por isso, existem várias maneiras de representar um grafo. Nesta série só vou usar as duas mais populares:

  • Matriz de Adjacência
  • Lista de Adjacência

Poderíamos falar também sobre a Matriz de Incidência, mas eu nunca precisei utilizá-la, então prefiro só entrar nessas duas mesmo.

Cada vértice é um número

Para representar um grafo, cada vértice sempre vai ser um número. No caso de você querer representar amizade entre duas pessoas, como no exemplo do Orkut no último artigo, você cria um vetor chamado nome[] que contém o nome de cada número... :)

Matriz de Adjacência

A matriz de adjacência é uma matriz de N x N (onde N é o número de vértices do grafo). Ela inicialmente é preenchida toda com 0 e quando há uma relação entre o vértice do x (número da coluna) com o do y (número da linha), matriz[x][y] é marcado um 1.

Vamos escrever este grafo aqui usando uma matriz de adjacência:

Matriz Inicial

  1 2 3 4 5
1 0 0 0 0 0
2 0 0 0 0 0
3 0 0 0 0 0
4 0 0 0 0 0
5 0 0 0 0 0

Relações do nosso grafo

Já que o grafo não é orientado, a relação 1-2 significa 2-1 também. :)

  • 1-2 (2-1)
  • 1-3 (3-1)
  • 2-3 (3-2)
  • 2-4 (4-2)
  • 4-5 (5-4)

Essas são as cinco arestas do nosso grafo. Vamos representá-la na matriz de adjacência:

  1 2 3 4 5
1 0 1 1 0 0
2 1 0 1 1 0
3 1 1 0 0 0
4 0 1 0 0 1
5 0 0 0 1 0

Simetria

Uma das características da matriz de adjacência quando o grafo não é orientado é a simetria encontrada na "diagonal". É interessante que se lermos uma coluna de índice v ou uma linha de índice v vamos encontrar a mesma coisa.

Problemas da OBI

Alguns desses programas são complicados, mas isto não entra em questão. Apenas dê uma olhada no recebimento da entrada deles. Todos estão em C. O que eles têm em comum é a utilização de uma matriz de adjacência para guardar o grafo (geralmente nomeada g):

* - Grafo orientado
+ - Grafo ponderado (veremos no próximo artigo)
X - Não queira ver esse problema. Nunca vi solução mais feia. Já estou providenciando uma implementação mais decente... ;)

Descobrir o grau de cada vértice

Eu não disse pra vocês que era fácil conseguir emprego no Orkut? Hehehe... Vamos pensar como podemos descobrir o grau (relembrando... o número de arestas que cada vértice tem OU o número de amigos que cada pessoa tem) na matriz de adjacências. Não basta contar quantos 1s tem na sua linha correspondente? Então façamos isto.

para i LaTeX: leftarrow{} 1 até N, faça
	grau LaTeX: leftarrow{} 0
	para j LaTeX: leftarrow{} 1 até N, faça
		se matriz[i][j] = 1, então
			grau LaTeX: leftarrow{} grau + 1
		fim-se
	fim-para
	imprima "O vértice " i " tem grau " grau "."
fim-para

O custo é LaTeX: \Theta{}(n^{2}) até no melhor caso... Será que não há uma maneira mais simples de fazer isso? Imagina um negócio do tamanho do Orkut. Milhões de pessoas... Não seria bem mais fácil se ao invés de termos que passar por todos os vértices, só passarmos pelos amigos? Não poderíamos colocar somente seus amigos num vetor? É por isto que utilizamos a lista de adjacência.

Lista de Adjacência

A lista de adjacência consiste em criar um vetor para cada vértice. Este vetor contém cada vértice que o vértice "conhece" (tem uma aresta para). Geralmente é representada com uma matriz, porque cada vértice vai precisar de um vetor diferente, não é? Já que eu não vou ser duas vezes "amigo" de ninguém, então podemos fazer uma matriz de NxN.

  1 2 3 4 5
1          
2          
3          
4          
5          

A lista consiste em escrever para cada número de linha (= vértice) seus amigos, da seguinte maneira:

  1. 2, 3
  2. 1, 3, 4
  3. 1, 2
  4. 2, 5
  5. 4

Portanto, na programação seria representado da seguinte maneira:

  1 2 3 4 5
1 2 3      
2 1 3 4    
3 1 2      
4 2 5      
5 4        

O método da lista de adjacências tem várias vantagens: dependendo de como você implementa você não precisa inicializar a lista (zerar), as buscas são bem mais rápidas (você só passa pelos vértices que são "amigos" do atual) e geralmente você já tem o grau do vértice na ponta da língua (eu, pelo menos, sempre uso um vetor cont que contém o número de amigos de cada vértice para ficar mais fácil inserir o próximo elemento na lista - lista[cont[v]++]=w).

Como implementar

Vamos trabalhar com uma entrada de vários x, y, indicando relação entre x-y (y-x) até que x=0 e y=0. O grafo não é orientado.

Matriz de Adjacências

para i LaTeX: leftarrow{} 1 até N, faça
	para j LaTeX: leftarrow{} 1 até N, faça
		matriz[i][j] LaTeX: leftarrow{} 0
	fim-para
fim-para

enquanto (recebe x, y e x LaTeX: neq{} 0), faça
	matriz[x][y] LaTeX: leftarrow{} 1
	matriz[y][x] LaTeX: leftarrow{} 1
fim-enquanto

Tem vários exemplos implementados em C aqui.

Lista de Adjacências

para i LaTeX: leftarrow{} 1 até N, faça
	grau[i] LaTeX: leftarrow{} 0
fim-para

enquanto (recebe x, y e x LaTeX: neq{} 0), faça
	lista[x][grau[x]++] LaTeX: leftarrow{} y
	lista[y][grau[y]++] LaTeX: leftarrow{} x
fim-enquanto

Para quem não programa em C, o variavel++ significa "incrementar variavel depois da instrução atual".

As duas juntas

para i LaTeX: leftarrow{} 1 até N, faça
	para j LaTeX: leftarrow{} 1 até N, faça
		matriz[i][j] LaTeX: leftarrow{} 0
	fim-para
	grau[i] LaTeX: leftarrow{} 0
fim-para

enquanto (recebe x, y e x LaTeX: neq{} 0), faça
	matriz[x][y] LaTeX: leftarrow{} 1
	matriz[y][x] LaTeX: leftarrow{} 1
	lista[x][grau[x]++] LaTeX: leftarrow{} y
	lista[y][grau[y]++] LaTeX: leftarrow{} x
fim-enquanto

Qual a representação que devo utilizar?

Isso depende totalmente do problema. Em alguns casos, o mais barato é usar as duas representações juntas. As vantagens da lista de adjacências eu já escrevi aqui. A única vantagem da matriz de adjacências é você em tempo constante (não é nem linear) saber se um vértice é amigo de outro. Afinal, basta testar matriz[v][w].

Até maio do ano passado, eu não tinha aprendido isso direito e sempre usava a matriz de adjacências. Por isso muitos dos meus problemas estão resolvidos de forma pouco eficiente...


Espero que tenham gostado. Qualquer dúvida, crítica ou sugestão; poste um comentário ou me envie um e-mail. Mandem um feedback!

Compare Preços de: notebooks, acer aspire, hp pavilion, computadores, pentium 4, nintendo wii, ps3, celulares, câmeras digitais

53 assinantes

Mais artigos

Comentários recentes

  • Matheus Eduardo Maura: Faço engenharia eletrica-eletronica( UNIRP SÃO JOSE DO RIO PRETO), e...
  • rafael: muito legal o artigo mas teria como resolver esse algoritmo nao consegui de jeito nenhum,...
  • Roger: Bom artigo. Podia atualizar esse site
  • Aline Celestrino Bento: o que É ALGORITMO=exemplo:35 :7 porque eu ñ sei ALINE
  • Claudio: eu gostaria de saber este algoritmo: faça um algoritmo que determine, para um digrafo,...
  • ingrid morgana gomes paes: que bacana que legau isso e emtesamte e legau para apremder mais a...
  • Filipe Névola: filipe.bico@hotmail. com
  • Filipe Névola: Boa noite, gostaria de saber se você tem alguma implementação de menor caminho...
  • Carlos Luiz Silva Meirelles: estou fazendo curso de informática gratuito patrocindo pelo estado....
  • Maria Regina de Queiroz: Olá Tiago, li os seus artigos e gostei muito, gostaria se possivel que...

Categorias

Escrevo também...

  • Tiago Madeira
    Site pessoal e blog do autor destes artigos
  • Mal Vicioso
    Blog sobre filosofia e sobre a hipocrisia da sociedade

Links

Sobre o design

Este design foi copiado do CSS Zen Garden e modificado com autorização de seu autor, Gunta Klavina.

Licença

Todo o conteúdo deste site (incluindo textos, imagens, arquivos de áudio e quaisquer outros trabalhos), exceto quando especificado o contrário, está licenciado por Tiago Madeira sob uma Licença Creative Commons.

HTML 4.01 gerado por WordPress em 0.452 segundos.