You are on page 1of 14

Universidade Federal de Ouro Preto

Instituto de Ciências Exatas e Biológicas

Departamento de Computação

Teoria dos Grafos


1a Competição de Caminhos Mínimos do Decom

Marco Túlio Reis Rodrigues


Rafael Henrique Vareto
Samuel Souza Brito

Professor - Haroldo Santos

Ouro Preto
25 de outubro de 2010
Sumário
1 Introdução 1
1.1 Considerações iniciais . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Descrição do Trabalho . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2.1 Regras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2.2 Regras de Implementação . . . . . . . . . . . . . . . . . . . . 1
1.2.3 Formato de Entrada/Saída e Parâmetros . . . . . . . . . . . . 2

2 Algoritmo e estruturas de dados 2


2.1 Algoritmo de leitura . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.2 Algoritmo de Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2.1 Estruturas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2.2 Função Refaz . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2.3 Função Constroi . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2.4 Função RetiraMin . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2.5 Função DiminuiChave . . . . . . . . . . . . . . . . . . . . . . 6
2.2.6 Função Insere . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2.7 Função RecPrint . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2.8 Função Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3 Algoritmo de Floyd-Warshall . . . . . . . . . . . . . . . . . . . . . . . 9
2.3.1 Função recPrint . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3.2 Função vericaCicloNegativo . . . . . . . . . . . . . . . . . . . 9
2.3.3 Função FWarshall . . . . . . . . . . . . . . . . . . . . . . . . . 10

3 Conclusão 12

Lista de Programas
1 Estrutura: Item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2 Estrutura: Heap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3 Função: Refaz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4 Função: Constroi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
5 Função: RetiraMin . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
6 Função: DiminuiChave . . . . . . . . . . . . . . . . . . . . . . . . . . 6
7 Função: Insere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
8 Função: RecPrint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
9 Função: Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
10 Função: recPrint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
11 Função: vericaCicloNegativo . . . . . . . . . . . . . . . . . . . . . . 10
12 Função: FWarshal . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2
1 Introdução
Este trabalho consiste em solucionar problemas reais relacionados à grafos com o
objetivo de encontrar a melhor rota possível entre dois pontos (vértices) considerando
o menor caminhos entre esses dois vértices.

1.1 Considerações iniciais

• Ambiente de Desenvolvimento do Código Fonte: GNU Compiler Collection


4.4.3;
• Linguagem Utilizada: Linguagem C, padrão GNU C;

• Ambiente de desenvolvimento da documentação: Kile Version 2.0.85 - Editor


de LATEX.

1.2 Descrição do Trabalho

1.2.1 Regras
• Os códigos serão checados quanto a sua corretude

• Os programas devem respeitar o formado de Entrada e Saída denido

• O código deve respeitar as regras de implementação

• Serão premiados os 3 primeiros colocados, do seguinte modo:

 nota do trabalho = nota máxima + 1;


 nota do trabalho = nota máxima + 0,5;
 nota do trabalho = nota máxima;
 os restantes serão avaliados de acordo com a correção normal de trabalhos;
 O grupo vencedor irá fazer uma apresentação para a turma descrevendo
sua implementação.

1.2.2 Regras de Implementação


Os códigos devem ser escritos em C, sem o uso de bibliotecas adicionais, exceto
a biblioteca padrão da linguagem ou da biblioteca GNU. Os seguintes padrões C são
aceitos:
• ANSI C 89

• ANSI C 99

• GNU C

1
1.2.3 Formato de Entrada/Saída e Parâmetros
O programa deve receber os seguintes argumentos, quando chamado pela linha
de comando:
prog <arquivoProblema> <nrExecuções> <agDepuração>
Onde <agDepuração> pode receber valor 0 ou 1. Como exemplo:
prog rome99.gr 1000 1
Indica que o programa irá ler o grafo do arquivo rome99.gr, executando o algo-
ritmo de caminhos mínimos 1000 vezes e ao nal irá imprimir/salvar informação de
depuração. A informação de depuração que deve ser gerada, quando solicitada, é a
seguinte:
arquivo spaths.txt
O arquivo spaths.txt deve conter todos os caminhos mínimos computados para
cada par de vértices (s,t), sendo s diferente de t. Cada linha contém a informação
sobre o caminho mínimo de um par (s,t), no formato:

[s, t](dist) n1 n2 n3 ... nn


Onde:
• s: nó fonte;

• t: nó destino;

• dist: distância calculada entre s e t;

• n1 n2 n3 ... nn: caminho computado entre s e t, incluindo todos os nós


intermediários no formato: s n2 n3 ... t.

2 Algoritmo e estruturas de dados


2.1 Algoritmo de leitura

Antes mesmo de usar os algoritmos de Dijkstra e Floyd-Warshall, precisamos


carregar todos os arquivos de entrada para a memória principal. Este processo pode
parece complexo, mas na verdade trata-se de algo bastante simples.
Logo no início do arquivo main.c, é predenido um modelo de uma estrutura
chamada de Dados, esta estrutura possui os campos origem, destino e custo, o
objetivo desta estrutura é armazenar todas as informações necessárias encontradas
no arquivo de entrada.
Em seguida, está a função main( int argc, char *argv[] ), função que precisa
de 3 parâmetros para que o programa possa funcionar corretamente, o primeiro
parâmetro trata-se do nome do arquivo de entrada, o segundo informa o número de
vezes que o programa deve executar o código e o terceiro é o ag de depuração.
Logo no início da função main(), são declaradas a maioria das variáveis que serão
usadas durante a execução do programa, de onde destacam-se: pDados(ponteiro para

2
um vetor da estrutura Dados), pMatrizGrafo(matriz responsável em armazenar as
intercessões vizinhas) e pMatrizCusto (matriz para armazenar o custo/valor para
cada intercessão vizinha);
O método de comparação if(argc != 4) realiza o teste a m de vericar se o
programa recebeu o número de parâmetros adequados para dar continuidade na
execução do programa. Logo em seguida, caso os parâmetros estejam certos, o
programa tentará abrir o arquivo de entrada cujo nome foi passado como parâmetro,
caso haja algum erro, o programa retorna a seguinte mensagem para o usuário:
Problemas na abertura do arquivo.
Durante o primeiro laço de repetição do programa, com o seguinte cabeçalho
while(c!=`a`) o programa evita todo o tipo de comentário e informações que não
são importantes para a leitura do arquivo e que não devem ser incorporados pelo
programa, neste mesmo laço de repetição, o programa carrega o número de arestas
e vértices para que possa ser feita, mais adiante, a alocação dinâmica de memória.
Com a alocação dinâmica de pDados e qtdVizinhos, onde qtdVizinhos armazena
o número de vizinhos de cada vértice, é necessário colocar em todas as posições
de qtdVizinhos valores nulos. No próximo laço de repetição while (!feof(arq)) o
programa vai incorporar todas as informações importantes contidas no arquivo de
entrada(todos os arquivos de entrada obedecem ao mesmo padrão) para o vetor da
estruta Dados(como já mencionado antes, chamado de pDados). Todos os valores
são seguramente copiados para os campos certos da estrutura. Logo após o término
do laço, o programa fecha o arquivo de entrada.
Agora que já temos todo o arquivo de entrada copiado para a memória, e já
sabemos o número de vizinhos de cada vértice é o momento de gerar a matriz de
vizinho (pMatrizGrafo) e a matriz de custo (pMatrizCusto). Primeiro alocamos as
duas matrizes com <nVertices> linhas e <qtdVizinhos> colunas, onde cada inter-
cessão possui um número diferente de vizinhos(ou seja, um numero diferente de
colunas). Na primeira posição(coluna) de cada matriz, são armazenadas o número
de vizinhos que já foram adicionados em cada linha (vértice), a partir da segunda
coluna de cada linha são adicionados vizinhos da intercessão atual.
Assim que as matrizes pMatrizGrafo e pMatrizCusto já foram carregadas e preenchi-
das, não é mais necessário a utilização de pDados, neste caso basta liberar a memória
utilizada por ele. Com o vetor do tipo pDados excluído, é preciso criar dois vetores,
um para armazenar a menor distância de uma intercessão qualquer até o ponto ini-
cial (vetor chamado de distancias) e o outro para armazenar a intercessão anterior
(vetor chamado anterior).
Com estes dois novos vetores criados e alocados dinamicamente na memória, o
programa analisa o terceiro parâmetro, caso o valor seja 1 o programa cria um ar-
quivo de saída com o resultado, caso contrário o programa simplesmente executa
as instruções sem salvar em um arquivo. A partir de agora o programa irá anal-
isar o segundo parâmetro e executar as funções encontradas no arquivo digraph.h
(exemplo: dijkstra() ou fwarshall) repetitivamente, onde esta repetição esta direta-
mente associada ao valor passado no segundo parâmetro. Ambas estas funções estão
denidas e detalhadas a seguir.

3
2.2 Algoritmo de Dijkstra

Suponha que você deseja encontrar o menor caminho entre duas interseções em
uma mapa de cidades, com um ponto de partida e outro de destino. A ordem é bem
simples: para iniciar, marque a distancia de todas as intercessões como innito(isto
signica que a intercessão não foi visitada ainda). Agora, em cada iteração, selecione
a intercessão atual. Na primeira iteração a intercessão atual será o ponto inicial e a
distancia para ele mesmo será nula. Para as iterações seguintes, a intercessão atual
terá o valor da intercessão ainda e não visitada e que também seja a mais próxima
do ponto inicial.
A partir da intercessão atual, atualize a distancia para cada intercessão ainda
não visitada que possui conexão direta com ela. Isto é feito calculando o somatório
da distancia entre uma intercessão não visitada e o valor da intercessão atual, e
alterando o valor(distancia) da intercessão não visitada caso a distancia seja menor
a distancia atual. Em outras palavras, a intercessão possui seu valor alterado se o
caminho até ao ponto inicial passando pela intercessão atual é menor que os outros
caminhos já conhecidos.
Continue este processo de atualização das intercessões vizinhas com a menor
distancia, depois marcando a intercessão atual como já visitada e movendo para
a intercessão não visitada mais próxima até que você tenha chegado ao ponto de
destino. Uma vez marcado o ponto de chegada como visitado signica que você
determinou o menor caminho para ele, a partir do ponto inicial(fonte).
Neste trabalho, o algoritmo de Dijkstra se encontra no arquivo digraph.c, na
verdade não só a função de Dijkstra, mas também várias outras funções auxiliares,
além de estruturas.

2.2.1 Estruturas
A estrutura Item é responsável em armazenar o número do vértice e seu respec-
tivo custo em relação lação à fonte.

// D e f i n i c a o da E s t r u t u r a Item

typedef struct
{

5 int vertice ;

int custo ;

} Item ;

Programa 1: Estrutura: Item


Já a outra estrutura representa o modelo de uma Heap, justicando assim o
seu nome. Heap é uma estrutura que possui dois campos, um deles é um ponteiro
para um possível vetor de Item e o outro armazena a quantidade/tamanho do vetor.
A Heap deve estar sempre ordenada de acordo com o menor custo, o elemento na
primeira posição da Heap sempre será o de menor custo.

// D e f i n i c a o da E s t r u t u r a Heap

typedef struct
{

4
5 Item ∗ fila ;

int qtde ;

} Heap ;

Programa 2: Estrutura: Heap

2.2.2 Função Refaz


A função Refaz() é chamada a quase todo o momento do programa com o obje-
tivo de reestruturar a Heap quando ela for alterada, isto é, garantir a todo momento
que o primeiro elemento seja sempre o de menor custo.

// D e f i n i c a o da Funcao Refaz

void Refaz ( int Esq , int Dir , Item ∗A)


{

5 int i = Esq ;

int j ;

Item aux ;

j = i ∗ 2;

aux = A[ i ] ;

10 while ( j <= Dir )

if ( j < Dir )

if (A [ j ] . c u s t o > A[ j + 1 ] . c u s t o )

15 j ++;

if ( aux . c u s t o <= A [ j ] . c u s t o )

break ;
A[ i ] = A[ j ] ;

20 i = j ;

j = i ∗ 2 ;

A[ i ] = aux ;

Programa 3: Função: Refaz

2.2.3 Função Constroi


Esta função, como o próprio nome diz contrói a Heap logo no início em que a
função dijkstra() é chamada.

// D e f i n i c a o da Funcao C o n s t r o i

void C o n s t r o i ( Item ∗A , int ∗ n )


{

5 int Esq ;

Esq = ∗n / 2;

while ( Esq >= 0)

R e f a z ( Esq , ∗n , A) ;

10 Esq −−;

5
}

Programa 4: Função: Constroi

2.2.4 Função RetiraMin


Esta função retira da Heap o elemento que possui o menor custo, ou seja, ele-
mento que se encontra na primeira posição, e logo depois se encarrega de chamar
a função Refaz() para reestruturar a Heap pois a mesma agora não possui mais o
elemento de menor custo da primeira posição.

// D e f i n i c a o da Funcao RetiraMin

int RetiraMin ( Item ∗A , int ∗ n , I t e m ∗ pMinimo )

5 if ( ∗n < 1)

return 0;

else
{

∗ pMinimo = A[ 1 ] ;

10 A[ 1 ] = A[ ∗n ] ;
( ∗ n ) −−;
Refaz ( 1 , ∗n , A) ;

return 1;

15 }

Programa 5: Função: RetiraMin

2.2.5 Função DiminuiChave


Esta é uma importante função do programa. Ela é responsável por atualizar o
custo dos vértices que estão na Heap. A cada vez que um novo caminho com um
custo menor é encontrado a função DiminuiChave entra pra fazer a atualização dos
valores que estão Heap.

// D e f i n i c a o da Funcao DiminuiChave

int DiminuiChave ( int i , int ChaveNova , Item ∗A)


{

5 Item aux ;

if ( ChaveNova > A [ i ] . c u s t o )

return 0;

A[ i ] . c u s t o = ChaveNova ;

while ( i > 1 && A [ i / 2 ] . c u s t o > A[ i ] . c u s t o )

10 {

aux = A[ i / 2 ] ;

A[ i / 2 ] = A[ i ] ;

A[ i ] = aux ;

i /= 2;

15 }

return 1;

6
Programa 6: Função: DiminuiChave

2.2.6 Função Insere


Esta função, inicialmente insere todos os valores na Heap, de uma forma tal que
o ultimo elemento é sempre inserido no nal da mesma.

// D e f i n i c a o da Funcao I n s e r e

void I n s e r e ( Item ∗x , Item ∗A , int ∗ n )


{

5 ∗ n ) ++;
(

A[ ∗ n ] = ∗x ;
A[ ∗ n ] . c u s t o = x −>c u s t o ;
}

Programa 7: Função: Insere

2.2.7 Função RecPrint


A recPrint() trata-se de uma função recursiva com o objetivo de imprimir o cam-
inho do vértice fonte (ponto de origem) até o sumidouro (ponto de chegada).

// D e f i n i c a o da Funcao RecPrint

void recPrint ( int ∗ p, int s , int t , FILE ∗ txt )

5 i f ( s == t || t < 0)

return ;
recPrint (p , s , p[ t ] , txt ) ;

i f ( p [ t ] >0)
f p r i n t f ( txt , " %d" , p[ t ]) ;

10 return ;
}

Programa 8: Função: RecPrint

2.2.8 Função Dijkstra


Com toda a certeza, esta é uma das funções mais importantes do programa.
Observe que são passados para esta função as matrizes pMatrizGrafo e pMatrizCusto,
mas que aqui recebem outros nomes: pMatGrafo e pMatCusto que armazenam para
cada elemento i os seus vizinhos j e os custos, respectivamente. S é o número do
vértice fonte, de onde o algoritmo vai se iniciar. O resultado do programa será
armazenado nos vetores dist e prev, que representam os vetores distancia e anterior,
passados por parâmetro.
Durante a execução desta função, perceba que a Heap é alocada dinamicamente
com o tamanho equivalente ao número de vértices. Logo após a construção da Heap,
chega a hora de construí-la, lembrando de que a primeira posição deve sempre conter
o elemento de menor custo.

7
Inicialmente, o vetor dist possui todos os seus elementos com valores innitos,
a não ser o vértice de origem que possui valor zero. Já o vetor prev possui todos
os seus elementos com valores negativos, mais especicamente -1, ou seja, nenhum
deles possuem intercessões anteriores inicialmente a não ser também o vértice de
origem que possui como vértice anterior ele mesmo.
No último laço de repetição (while(tam > 0)), inicialmente, todos os vértices já
se encontram na Heap com distância innita e á medida que os vértices são explo-
rados e as distâncias encontradas são menores que a distância atual, essa distância
é atualizada para o vértice. A cada iteração o elemento de menor custo é retirado
da Heap e todos os seus vizinhos são explorados. A cada exploração podemos ter a
atualização de elementos do vetor dist e da heap.

// D e f i n i c a o da Funcao D i j k s t r a

void dijkstra ( int ∗∗ pMatGrafo , int ∗∗ pMatCusto , int S, int nVert , int
nArest , int ∗ d i s t , int ∗ p r e v , int ∗ q t d V i z i n h o s )
{

5 int i , j ;

Item ∗ heap ;

int pos ;

Item aux , u , v;

int tam = 0 ;

10
h e a p =( I t e m ∗ ) m a l l o c ( nVert ∗ ( s i z e o f ( Item ) ) ) ;
C o n s t r o i ( h e a p ,& tam ) ;

for ( i = 0 ; i <n V e r t ; i ++)


{

15 dist [ i ] = INT_MAX/ 3 ;

prev [ i ] = − 1;
}

for ( i = 1 ; i <n V e r t ; i ++)


{

20 i f ( i != S )
{

aux . c u s t o = INT_MAX/ 3 ;

aux . v e r t i c e = i ;

I n s e r e (&aux , h e a p ,& tam ) ;

25 }

else
{

dist [S] = 0;

prev [ S ] = S;

30 aux . c u s t o = 0 ;

aux . v e r t i c e =S ;

I n s e r e (&aux , h e a p ,& tam ) ;

35 while ( tam > 0)

R e t i r a M i n ( h e a p ,& tam ,& v ) ;

for ( i = 1 ; i <=q t d V i z i n h o s [ v . v e r t i c e ] ; i ++)

40 u. vertice = pM a tG r af o [ v . v e r t i c e ] [ i ] ;

u . custo = pMatCusto [ v . v e r t i c e ] [ i ] ;

if ( ( dist [u. vertice ]) > ( dist [v. vertice ] + pMatCusto [ v . v e r t i c e ] [ i

8
]) )

dist [u. vertice ] = dist [v. vertice ] + pMatCusto [ v . v e r t i c e ] [ i ] ;

45 prev [ u . v e r t i c e ] = v. vertice ;

for ( j = 1 ; j <=tam ; j ++)


{

i f ( heap [ j ] . v e r t i c e==u . v e r t i c e )

50 DiminuiChave ( j , d i s t [ u . v e r t i c e ] , heap ) ;

break ;
}

55 }

f r e e ( heap ) ;

Programa 9: Função: Dijkstra

2.3 Algoritmo de Floyd-Warshall

O algoritmo de Floyd-Warshall recebe como entrada uma matriz de adjacência


que representa um grafo (V,E) orientado cujo as arestas possuem valores (pesos).
O valor de um caminho entre dois vértices é a soma dos valores de todas as arestas
ao longo desse caminho. As arestas E do grafo podem ter valores negativos, mas o
grafo não pode conter nenhum ciclo de valor negativo. O algoritmo calcula, para
cada par de vértices, o menor de todos os caminhos entre os vértices.

2.3.1 Função recPrint


Tem a mesma funcionalidade da função recPrint do algoritmo de Dijkstra. Im-
prime o caminho entre dois vértices origem e destino.
// D e f i n i c a o da Funcao r e c P r i n t

void r e c P r i n t ( Item ∗∗ p, int s , int t , FILE ∗ txt )

5 if (s == t || t <0)

return ;
}

recPrint (p , s , p [ s ] [ t ] . prev −1 , txt ) ;

10 i f ( p [ s ] [ t ] . p r e v >0)
f p r i n t f ( txt , " %d" , p [ s ] [ t ] . prev ) ;

return ;
}

Programa 10: Função: recPrint

2.3.2 Função vericaCicloNegativo


Caso a função vericaCicloNegativo() encontre algum ciclo no grafo com custo
negativo, a mesma retorna o valor um, caso contrário retorna zero.

9
// D e f i n i c a o da Funcao v e r i f i c a C i c l o N e g a t i v o
int v e r i f i c a C i c l o N e g a t i v o ( I t e m ∗∗ d , int i )
{

i f (d [ i ] [ i ] . dist < 0)

5 return 1 ;
return 0 ;
}

Programa 11: Função: vericaCicloNegativo

2.3.3 Função FWarshall


Esta função também se enquadra entre as funções mais importantes do programa.
Note que para a função fwarshall() são passados por parâmetros o número de vértices
do grafo (nVert), um ponteiro para a matriz MatrizGrafo e também ponteiros para
matrizes de valores antecessores (prev) e distâncias (dist).
Observe que no primeiro laço de repetição do programa, a matriz dist possui
todos os seus elementos com valores innitos enquanto a matriz prev possui seus
elementos com o valor -1, perceba também que neste mesmo laço, todos os elementos
das diagonais principais das duas matrizes possuem o valor nulo ou -1.
No laço seguinte, este algoritmo compara todos os caminhos possíveis através do
grafos entre cada par de vértices. Sendo que executa esta operação O(V 3 ) compara-
ções em um grafo, onde V representa o número total de vértices.
Note que existe um parâmetro denominado neg que informa se existe algum par
de vértices com custo negativo. Se não houver, executa uma parte do algoritmo,
sem vericações de ciclo negativo. Se durante a leitura dos dados existir algum par
de vértices com custo negativo então a função verica se existem ciclos negativos no
grafo. Se um ciclo negativo é encontrado, a execução é encerrada.
// D e f i n i c a o da Funcao FWarshal
void FW a rs ha l ( int nVert , int32_t ∗∗ MatrizGrafo , Item ∗∗ data , int neg )

re gi ste r int i , j , k;

5 FILE ∗ arq ;

Item aux ;

for ( i = 0 ; i <n V e r t ; i ++)


{

10 for ( j = 0 ; j <n V e r t ; j ++)


{

i f ( MatrizGrafo [ i ][ j ] == INF_MIN )

data [ i ] [ j ] . d i s t = INF_MAX ;

15 data [ i ] [ j ] . prev = − 1;
}

else
{

data [ i ] [ j ] . d i s t = MatrizGrafo [ i ] [ j ] ;

20 data [ i ] [ j ] . prev = i +1;

data [ i ] [ i ] . d i s t = 0;

d a t a [ i ] [ i ] . p r e v= − 1;
25 }

10
i f ( neg >= 1)

for ( k = 0 ; k<n V e r t ; k++)


30 {

for ( i = 0 ; i <n V e r t ; i ++)


{

for ( j = 0 ; j <n V e r t ; j ++)


{

35 aux . d i s t = data [ i ] [ k ] . d i s t + data [ k ] [ j ] . d i s t ;

i f ( aux . d i s t < data [ i ] [ j ] . d i s t )

aux . p r e v = data [ k ] [ j ] . prev ;

data [ i ] [ j ] = aux ;

40 if ( i == j )

i f ( v e r i f i c a C i c l o N e g a t i v o ( data , i ))

i f ( ( arq = fopen ( " s p a t h s . t x t " , "w" ) ) ==

NULL)

45 {

perror ("Nÿo f o i p o s s à v e l c r i a r o
arquivo spaths . t x t ") ;
}

f p r i n t f ( arq , "[%d,%d ](% d ) " , i +1 , i +1 ,

data [ i ] [ i ] . d i s t ) ;

r e c P r i n t ( data , i , data [ i ] [ i ] . prev , arq )

50 f p r i n t f ( arq , " %d" , d a t a [ i ] [ i ] . prev ) ;

f p r i n t f ( arq , " %d\n" , i +1) ;


f c l o s e ( arq ) ;

goto finaliza ;

55 }

60 }

else
{

for ( k = 0 ; k<n V e r t ; k++)


{

65 for ( i = 0 ; i <n V e r t ; i ++)


{

for ( j = 0 ; j <n V e r t ; j ++)


{

aux . d i s t = data [ i ] [ k ] . d i s t + data [ k ] [ j ] . d i s t ;

70 i f ( aux . d i s t < data [ i ] [ j ] . d i s t )

data [ i ] [ j ] = aux ;

75 }

finaliza : 1;

Programa 12: Função: FWarshal

11
3 Conclusão
Foi muito interessante a realização deste trabalho. Acredito que, de todos os
trabalhos práticos desenvolvidos até hoje durante o decorrer da graduação, esse foi
o que mais agregou conhecimento para nós. O fator da competição gera uma vontade
de fazer o melhor algoritmo, o mais rápido. E, com isso, conseguimos adquirir muito
conhecimento tanto na área de Grafos, quanto na área de otimização de algoritmos.

12

You might also like