Sei sulla pagina 1di 9

Universidade Federal do Vale do São Francisco

Implementação de busca em largura e em profundidade, algoritmo do menor caminho de Dijkstra: o caso do metrô de Paris

Ângelo Gustavo Gomes Cavalcanti Daise Farias dos Santos Eliezer Neto Fernandes Andrade Thaminne Felix de Oliveira Lopes Machado

Juazeiro, 2013

1.

Resumo

Neste trabalho veremos uma aplicação prática do algoritmo de dijkstra, algoritmo que toma a decisão que parece ótima no momento, desenvolvida através da linguagem C, no intuito de solucionar o problema de trajeto das estações do metrô de Paris, mostrando o caminho mais curto, onde o usuário informará o local de partida e o local da chegada e o software calculará e mostrará o trajeto mais curto, a partir das informações de distancia das linhas do metrô extraídas de um arquivo de texto.

2. Problema

Para a teoria dos grafos uma "estratégia gulosa" é conveniente já que sendo P um menor caminho entre 2 vértices U e V, todo sub-caminho de P é um menor caminho entre 2 vértices pertencentes ao caminho P, desta forma construímos os melhores caminhos dos vértices alcançáveis pelo vértice inicial determinando todos os melhores caminhos intermediários. Nota: diz-se 'um menor caminho' pois caso existam 2 'menores caminhos' apenas um será descoberto. O algoritmo considera um conjunto S de menores caminhos, iniciado com um vértice inicial I. A cada passo do algoritmo busca-se nas adjacências dos vértices pertencentes a S aquele vértice com menor distância relativa a I e adiciona-o a S e, então, repetindo os passos até que todos os vértices alcançáveis por I estejam em S. Arestas que ligam vértices já pertencentes a S são desconsideradas. Um exemplo prático do problema que pode ser resolvido pelo algoritmo de Dijkstra é: alguém precisa se deslocar de uma cidade para outra. Para isso, ela dispõe de várias estradas, que passam por diversas cidades. E informa qual dos trajetos oferece o menor caminho.

3. Busca em profundidade

Busca em profundidade (ou busca em profundidade, também usada à sigla em inglês DFS) é um algoritmo usado para realizar uma busca ou travessia numa árvore, estrutura de árvore ou grafo. Intuitivamente, o algoritmo começa num nó raiz (selecionando algum nó como sendo a raiz, no caso de um grafo) e

explora tanto quanto possível cada um dos seus ramos, antes de retroceder (backtracking).

O algoritmo de Busca em Profundidade é uma proposta que trabalha sob o

critério LIFO (Last In First Out, isto é, o último que entra é o primeiro que sai). É também denominada de primeiro-em-profundidade ou “depth-first” [RAB95]. Quanto à estrutura do algoritmo, a única diferença em relação à busca em largura, é a utilização de uma pilha ao invés de fila. Esta técnica explora o caminho para o objetivo, dando preferência aos nós que estão mais distantes da raiz da árvore de busca. Funciona bem, quando as soluções são total e igualmente desejadas ou quando anteriormente foi feita uma varredura, detectando direções incorretas [FUR73]. A busca em profundidade é usada quando a ideia é iniciar a busca a partir do ultimo estado gerado. A estratégia consiste em pesquisar o grafo o mais “profundamente” sempre que possível. Aplicável tanto a grafos orientados quanto não orientados. Possui um numero enorme de aplicações:

Determinar os componentes de um grafo

Ordenação topológica

Determinar componentes fortemente conexos

Sub-rotina para outros algoritmos

4. Busca em Largura Na teoria dos grafos, busca em largura (ou busca em amplitude, também

conhecido em inglês por Breadth-First Search (BFS)) é um algoritmo de busca em grafos utilizado para realizar uma busca ou travessia num grafo e estrutura

de dados do tipo árvore. Intuitivamente, você começa pelo vértice raiz e explora

todos os vértices vizinhos. Então, para cada um desses vértices mais próximos, exploramos os seus vértices vizinhos inexplorados e assim por diante, até que ele encontre o alvo da busca.

O algoritmo de Busca em Largura é uma proposta que trabalha sob o critério

FIFO (First In First Out, isto é, o primeiro que entra é o primeiro que sai). É também denominada de busca em amplitude, busca em nível e “breadth-first”

[RAB95].

Funciona da seguinte forma: “Aplica-se todos os operadores possíveis à raiz (isto é, ao estado inicial), em seguida, a todos os filhos da raiz (da esquerda para a direita), depois, a todos os “netos” da raiz (da esquerda para a direita) e assim por diante. A busca cessa ao se descobrir o nó objetivo.” [COL88]. Existem duas filas de trabalho usadas pela busca em largura. A fila de abertos, que guarda todos os vértices do grafo a serem explorados; e a fila de fechados, onde se encontram todos os vértices que já foram explorados. Neste algoritmo, todos os vértices de certo nível da árvore são examinados antes do nível abaixo. Se existe uma solução e se o grafo é finito, então por este método ela certamente será encontrada. Se pretender iniciar a busca a partir de estados gerados há algum tempo é recomendável à utilização da busca em amplitude

5. Problema do Caminho mais Curto Quando existe um destino a se chegar, podem existir vários caminhos possíveis até ele. Se o problema for definir o caminho para sair de um vértice A e alcançar um vértice B, não importa a ordem dos nós passados pelo caminho, mas o somatório das distâncias sendo o menor possível. Pode-se perceber que isso não é muito fácil de resolver, pois existem vários caminhos possíveis desconsiderando as distâncias, mas somente um resolve o problema. Então para definir qual é o caminho correto, o menor caminho possível nesse caso, primeiro é preciso saber quais são os caminhos possíveis, ou seja, em quais ordens o destino pode ser atendido passando por diferentes caminhos (nós). Tendo-se definido a ordem para passar por todos os caminhos possíveis, determinar o menor caminho entre eles fica fácil, bastando usar o algoritmo para isso. Assim, é possível perceber que o número de caminhos possíveis é o resultado do número de combinações possíveis entre o estado atual e o destino. A única maneira de saber qual desses possíveis caminhos representa o mais curto, é sabendo o comprimento de cada um deles. Isto, em muitos casos, se torna impraticável, pois para determinar o comprimento de cada um dos possíveis caminhos, é preciso aplicar o algoritmo e encontrar o menor caminho entre cada um dos vértices integrantes do caminho, na ordem em que eles são apresentados.

6. Algoritmo de Dijkstra

O algoritmo de Dijkstra, concebido pelo cientista da computação holandês

Edsger Dijkstra em 1956 e publicado em 1959, soluciona o problema do caminho mais curto num grafo dirigido ou não dirigido com arestas de peso não negativo, em tempo computacional O([m+n]log n) onde m é o número de arestas e n é o número de vértices. O algoritmo que serve para resolver o mesmo problema em um grafo com pesos negativos é o algoritmo de Bellman-Ford, que possui maior tempo de execução que o Dijkstra. O algoritmo de Dijkstra assemelha-se ao BFS, mas é um algoritmo guloso, ou seja, toma a decisão que parece ótima no momento. Escolhido um vértice como raiz da busca, este algoritmo calcula o custo

mínimo deste vértice para todos os demais vértices do grafo. O algoritmo pode ser usado sobre grafos orientados (dígrafos), ou não, e admite que todas as arestas possuam pesos não negativos (nulo é possível). Esta restrição é perfeita mente possível no contexto de redes de transportes, onde as arestas representam normalmente distâncias ou tempos médios de percurso; poderão existir, no entanto, aplicações onde as arestas apresentem pesos negativos, nestes casos o algoritmo não funcionará corretamente. (NONATO, 2004) Um exemplo prático do problema que pode ser resolvido pelo algoritmo de Dijkstra é: alguém precisa se deslocar de uma cidade para outra. E ele pode ser empregado em vários contextos, desde o estudo de uma cadeia de produção até o clássico problema do carteiro que não pode passar duas vezes

na mesma rua.

A matriz de vínculos e pesos pode ser composta por informações que

representam distância entre localidades, custos operacionais, quantidade de

recursos, ou qualquer outro elemento passível de ser ponderado entre os vértices. Por sua vez, os vértices também podem assumir uma infinidade de possibilidades. Os vértices podem representar cidades ou qualquer outra localidade, podem ser os estados em um sistema dinâmico complexo, ou mesmo abstrações de momentos em um contexto. Qualquer situação que possa ser representada por um grafo simples, que

possuas sua matriz de pesos definida é passível de ser submetido à proposta

de Dijkstra.

7. Estrutura de Dados Utilizada As TAD utilizadas seguem abaixo:

struct line{

int Node;

};

A

estrutura 'line' representa as linhas do metrô.

struct temporary_line{ int Node; float f;

};

A

estrutura 'temporary_line' representa uma linhatemporária, para trocas e

auxílio nas manipulações necessárias. struct Node{ int info; struct Node *next;

};

A

estrutura 'Node' representa o nó do grafo, ou seja, cada parada da linha.

struct Node* createNode()

{

 

return malloc(sizeof (struct Node));

}

A

estrutura acima é responsável pela criação dos nós em tempo de execução.

O grafo foi armazenado em arquivos texto, com correnpondencias entre suas distancias em cada nó da linha. O projeto conta com três arquivos que

descrevem os caminhos e as distâncias de cada linha. Os arquivos são matrizes de adjacências, mostrando as ligações entre as linhas. Foi adotado um padrão para as cores das linhas, onde a 1 é azul, a 2 é vermelha, a 3 é verde e a 4 é amarela. O arquivo 'Caminhos.txt' é uma matriz que mostra as linhas de acordo com suas cores:

0 1 0 0 0 0 0 0 0 0 0 0 0 0

1 0 1 0 0 0 0 0 4 4 0 0 0 0

0

0 1 0 1 0 0 3 0 0 0 0 3 0

0

0 0 1 0 1 4 4 0 0 0 0 0 0

0

0 0 0 1 0 0 0 0 0 0 0 0 0

0

0 0 0 4 0 0 0 0 0 0 0 0 0

0

0 0 3 4 0 0 0 4 0 0 3 0 0

0

4 2 0 0 0 0 4 0 0 2 0 0 0

0

4 0 0 0 0 0 0 0 0 0 0 0 0

0

0 0 0 0 0 0 0 2 0 0 0 0 0

0

0 0 0 0 0 0 3 0 0 0 0 0 0

0

0 2 3 0 0 0 0 0 0 0 0 0 3

0

0 0 0 0 0 0 0 0 0 0 0 3 0

O arquivo 'Dados.txt' é o responsável por guardar as informações dos vizinhos, ou seja, quem está ligado diretamente a determinado nó:

2

1,3,9,10

2,4,9,13

3,5,8,13

4,6,7,8

5

5

4,5,9,12

2,3,8,11

2

9

8

3,4,14

13

0

O último arquivo utilizado foi o 'Distâncias.txt', que mostra a distâncias dos arcos para cada nó em forma de matriz:

00

11 20 27 40 43 39 28 18 10 18 30 30 32

11

00 09 16 29 32 28 19 11 04 17 23 21 24

20

09 00 07 20 22 19 15 10 11 21 21 13 18

27

16 07 00 13 16 12 13 13 18 26 21 11 17

40

29 20 13 00 03 02 21 25 31 38 27 16 20

43

32 22 16 03 00 04 23 28 33 41 30 17 20

39

28 19 12 02 04 00 22 25 29 38 28 13 17

28

19 15 13 21 23 22 00 09 22 18 07 25 30

18

11 10 13 25 28 25 09 00 13 12 12 23 28

10

04 11 18 31 33 29 22 13 00 20 27 20 23

18

17 21 26 38 41 38 18 12 20 00 15 35 39

30

23 21 21 27 30 28 07 12 27 15 00 31 37

30

21 13 11 16 17 13 25 23 20 35 31 00 05

32

24 18 17 20 20 17 30 28 23 39 37 05 00

8.

Material e Método

O

software foi desenvolvido em linguagem C, e consiste no cálculo do trajeto

mais curto entre as estações do metrô de Paris. Esse metrô possui 14 estações

que estão interligadas em quatro linhas, sendo elas a linha amarela, vermelha,

azul e verde. São dadas as distâncias entre as estações, tempo de troca de linha e velocidade do trem.

O local de partida e o local de chegada é informado pelo usuário e mostra

como resultado as linhas de trajeto mais curto.

O ambiente integrado de desenvolvimento (IDE) utilizado para o

desenvolvimento deste sistema foi o Dev 5.3.0.4.

9. Resultados

Implementar a busca foi desafiador e inovador para todos os integrantes da equipe, a busca por alternativas e melhoramentos foi motivadora para a melhor solução.

Em relação a usabilidade do programa desenvolvido, concluimos que necessita

de algumas modificações, como novo cálculo de rota, em caso de mudança em

tempo de execução, deixando o programa mais flexível a alterações de caminho.

10. Referências Bibliográficas SEDGEWICK, Robert, 1946 Algorithms in C / Robert Sedgewick. - 3rd ed. - Reading, Mass.: Addison- Wesley, c1998. AARON M. Tenanbaum, Yedidyah Langsam, Mosha J. Augenstein; Estruturas de Dados Usando C, Pearson Makron Books, 2005. ZIVIANE, Nívio, 2004 Projetos de Algoritmos. SAYÃO, L. F. Modelos teóricos em ciência da informação: abstração e método científico. Ciência e Informação. v. 30, n. 1, p. 82-91, jan./abr. 2001 DOUGLAS D. MOONEY, A course in mathematical modeling, Mathematical Association of America, (1999) T. CORMEN H, LEISERSON, C. E. e RIVEST R. L, Algoritmos - Teoria e Prática, Editora Campus, 2002. Disponível em, http://pt.wikipedia.org/wiki/Busca_em_profundidade, acesso em

28/04/13

28/04/13

28/04/13

28/04/13

Disponível em,

Dijkstra, acesso em 28/04/13