Você está na página 1de 23

FlyFood

Hermano Diogenes Ferreira Costa


Universidade Federal Rural de Pernambuco - UFRPE
hermanodfc@gmail.com

July 14, 2021

Abstract

O presente trabalho tem por objetivo introduzir noções sobre complexidade computacional usando, como
plano fundo, o problema do caixeiro viajante - PCV. Adicionalmente, é feita uma introdução sobre a in-
viabilidade de utilização de algoritmos de busca exaustiva para encontrar a melhor solução possı́vel para
o problema, considerando o crescimento fatorial do espaço de busca. Por fim, é apresentada uma meta-
heurı́stica - Algoritmos Genéricos - como alternativa para encontrar uma solução suficientemente boa em um
tempo aceitável para uma entrada de tamanho 280 do PCV.

Keywords— TSP, complexidade, algoritmo genético, busca exaustiva, fitness, caixeiro viajante

1 Introdução

1.1 Apresentação e Motivação

Os serviços de entrega de comida têm se tornado cada vez mais demandados, no mundo inteiro, pois propor-
cionam comodidade e economia de tempo aos seus usuários. Segundo estudo da Statista Digital Market Outlook1 , o
tamanho do mercado mundial de entrega de comidas online, em 2019, era de cerca de US$ 107,4 bilhões. Para 2024,
as projeções apontam para um mercado de US$ 182,3 bilhões. No Brasil, segundo a Associação Brasileira de Bares e
Restaurantes - abrasel2 , este mesmo mercado movimentou, em 2019, R$ 11 bilhões e apresenta crescimento médio de
12% ao ano.

Desde o final de 2019, como consequência da pandemia de Covid-19, os negócios têm sido fortemente impacta-
dos pela aceleração digital3 . Nas palavras de Silvio Meira4 , já estamos em 2025. A partir desta perspectiva e analisando
o cenário atual, é necessário, para a sobrevivência das organizações nesta nova era, que sejam criados serviços verdadeira-
mente inovadores e transformadores. É neste contexto, da inovação em um mercado em expansão, que apresentamos o
FlyFood - um serviço de entrega de comida que utiliza drones.

Se, por um lado, o FlyFood representa o que há de mais moderno nas tecnologias utilizadas nos serviços de
entrega de comida, por outro, o principalmente problema inerente a este tipo de serviço ainda permanece: como escolher
a melhor rota para realizar as entregas?
1 ”eServices Report 2020 - Online Food Delivery — Statista.” https://www.statista.com/study/40457/food-delivery/. Aces-

sado em 21 de abril de 2021.


2 ”Delivery movimenta R$11 bilhões por ano - Abrasel.” https://abrasel.com.br/noticias/noticias/delivery-movimenta-

r-11-bilhoes-por-ano-enquanto-franquias-de-alimentacao-diversificam-a-oferta-de-produtos/. Acessado em 21 de abril


de 2021.
3 ”Brazilian Food Delivery Market 2020 - COVID-19 ... - PR Newswire.” https://www.prnewswire.com/news-releases/

brazilian-food-delivery-market-2020----covid-19-has-accelerated-brazils-digital-transformation-301205319.html.
Acessado em 21 de abril de 2021.
4 ”21 anotações sobre 2021 – dia a dia, bit a bit - por Silvio Meira.” https://silvio.meira.com/silvio/21-anotacoes-sobre-

2021/. Acessado em 21 de abril de 2021.

1
Certamente, a partir da resposta a esta pergunta, teremos a base para tratar de maneira efetiva os problemas
que o FlyFood enfrentará e cujo foco estão além do escopo deste trabalho:

(a) Como fazer a entrega no menor tempo possı́vel?


(b) Como fazer a entrega no menor custo possı́vel?
(c) Como reduzir o desgaste dos equipamentos?
(d) Qual o tamanho da menor frota necessária para entender a demanda corrente, ao menor custo possı́vel e mantendo
em nı́veis elevados a satisfação dos clientes?

1.2 Formulação do problema

Inicialmente, cabe destacar que o FlyFood é uma instância de um dos mais populares e estudados problemas
combinatoriais da computação, o problema do caixeiro viajante (the traveling salesman problem - TSP ): dado um conjunto
de cidades, um caixeiro viajante tenta encontrar o menor (ou o mais próximo do menor) circuito para visitar todas as
cidades uma única vez e retornar, ao final, ao ponto inicial.

Para solução do FlyFood, os dados de entrada para o problema serão fornecidos através de uma matriz M , no
formato m x n:

p(1,1) p(1,2) . . . p(1,n)

p(2,1) p(2,2) . . . p(2,n)
M(m,n) = . (1)

.. ..
..

. . . . .

p p ... p
(m,1) (m,2) (m,n)

A partir da matriz do problema (1), a posição ocupada por cada um de seus elementos indicará a sua coordenada
(linha, coluna). Por exemplo, o elemento p(1,1) possui coordenada (1, 1), ou seja, ocupa a linha 1 da coluna 1. Por sua
vez, o elemento p(i,j) ocupa a linha i da coluna j, possuindo coordenada (i, j).

Na matriz (1), cada elemento p(i,j) poderá assumir os seguintes valores:



0,
 se p(i,j) não é ponto de entrega ou ponto de origem/retorno
p(i,j) = n, se p(i,j) é ponto de entrega e n > 0

−1, se p(i,j) é ponto de origem/retorno

Dos valores p(i,j) presentes na matriz (1), dois subconjuntos são de interesse para a resolução do problema. O
conjunto dos pontos de entrega (Pe ) - os locais nos quais o drone fará uma entrega. E o conjunto contendo o ponto de
origem (Po ) - o local a partir do qual o drone iniciará sua jornada e para o qual deverá retornar ao concluir todas as
entregas. Para propiciar melhor entendimento, o ponto p(i,j) = −1 será chamado de R.

Pe = {v1 , v2 , . . . , vk } (2)
Sendo vi = p(x,y) , ∀i, j, vi 6= vj e i, j <= k, sendo k a quantidade de elementos do conjunto Pe , ou seja |Pe |.

Po = {p(x,y) } (3)

Sendo p(x,y) = R.

Assim, uma solução para o FlyFood é uma circuito partindo de p(x,y) = R (3), passando por todos os pontos de
entrega, ou seja, visitando todos os elementos do conjunto Pe (2), e, finalmente, retornando para o ponto de origem (3).
Nesta formulação, considerando, por uma questão de desempenho, que circuitos inversos não precisam ser calculadas e,
também, que uma solução é uma permutação dos elementos de (2), teremos |Pe |!/2 possı́veis soluções.

Para ser possı́vel quantificar a qualidade de uma possı́vel solução é necessário calcular o seu custo. No presente
trabalho, será calculada a distância total percorrida pelo drone na rota escolhida. Antes, contudo, é necessário definir
como calcular a distância entre dois pontos do circuito. Aqui, utilizaremos a distância euclidiana:
p
d(p(i,j) ,p(k,l) ) = (k − i)2 + (l − j)2 (4)

2
Portanto, sendo s uma possı́vel solução, ou seja, um elemento pertencente ao conjunto S composto pelas tuplas
ordenadas formadas pelas permutações dos elementos de Pe (2) e s = (s1 , s2 , . . . , si ), sendo si = p(a,b) , p(a,b) ∈ Pe ,
∀i, j, si 6= sj e i = |Pe |, teremos:
i−1
X
custo(s, R) = d(R, s1 ) + d(si , R) + d(sn , sn+1 ) (5)
n=1

Por fim, realizada uma busca exaustiva em todos os elementos de S e calculado os custo de cada um dos
circuitos s, o circuito solução (ss ) do problema será aquele que apresentar o menor custo possı́vel:
ss = argmin(custo, S, R) (6)

1.3 Objetivos

O objetivo principal deste trabalho é desenvolver um algoritmo capaz de minimizar a distância percorrida pelo
drone FlyFood durante a realização das entregas. Solucionado este problema, outros indicadores de desempenho serão
influenciados positivamente.

2 Referencial Teórico

2.1 Classes de Complexidade

2.1.1 Conceitos preliminares

Antes de adentrarmos na definição das classes de complexidade, faz-se necessária a apresentação de alguns
conceitos para melhor entendimento do tema. Dentre eles, o conceito de (a) algoritmo de verificação e (b) redução.

Segundo Cormen[1], um algoritmo de verificação é definido como sendo um algoritmo A com dois argumen-
tos, no qual um argumento é uma string de entrada x e o outro é uma string y chamada de certificado. O algoritmo
A verifica uma string x se existe um certificado y tal que A(x, y) = 1. A linguagem verificada pelo algoritmo A é:
L = {x ∈ {0, 1}∗ : existe y ∈ {0, 1}∗ tal que A(x, y) = 1}

Assim, um algoritmo a verifica uma linguagem L se para qualquer string x ∈ L, existe um certificado y que A
pode usar para provar que x ∈ L, não existindo tal certificado caso x 6∈ L. Por exemplo, no FlyFood, um problema da
classe NP-Hard, a rota com melhor custo seria este certificado.

Ainda segundo Cormen[1], o conceito de redução pode ser, intiutivamente, visto como a possibilidade de um
problema Q ser reduzido a outro problema Q0 se qualquer instância de Q pode facilmente ser remodelada como uma
instância de Q0 , que fornece soluções para a instância de Q. Por exemplo, a solução de equações lineares (ax + b = 0),
pode ser reduzido ao problema de solucionar equações quadráticas (0x2 + ax + b = 0). Além disso, é possı́vel perceber
que solucionar o problema Q não é mais difı́cil do que solucionar o problema Q0 .

2.2 Classe P

Conforme Ullman[2], as classes de complexidade são determinadas pelo modelo de computação, pelo modo de
computação (determinı́stico ou não determinı́stico), pelo uso do recurso a ser aferido (tempo ou espaço) e por um limite
(uma função de N em N).

Assim, numa abordagem mais formal para a definição da classe P , seja M T uma máquina de Turing deter-
minı́stica, ou seja, para cada entrada existe apenas um único estado para o qual a máquina pode fazer uma transição, e
f (n) sua função limite, a classe de complexidade DT IM E(f (n)) é definida por:
DT IM E(f (n)) = {L|L é decidı́vel por uma M T M tal que TM (n) é O(f (n))}

3
Assim, a classe P é o conjunto de linguagens que são decidı́veis em tempo polinomial por uma M T :
[
P = DT IM E(nk )
k≥1

Complementando esta definição, de acordo com Cormen[1], a class P é composta pelos problema que podem
ser solucionados em tempo polinomial (O(nk )), para alguma constante k, sendo n o tamanho da entrada do problema.
Além disso, se L ∈ P , então L ∈ N P , visto que se existe um algoritmo de tempo polinomial para decidir sobre L, o
algoritmo pode ser facilmente modificado para um algoritmo de verificação que simplesmente ignora qualquer certificado
(entrada y) e aceita exatamente aquelas entradas que realmente estão em L. Assim, P ⊆ NP.

2.3 Classe NP

Conforme Ullman[2], seja N uma máquina de Turing não determinı́stica, ou seja, para cada entrada existe um
conjunto de estado para o qual a máquina pode fazer uma transição, e f (n) sua função limite, a classe de complexidade
N T IM E(f (n)) é definida por:

N T IM E(f (n)) = {L|L é decidı́vel por uma NTM N tal que TN (n) é O(f (n))}

Assim, a classe N P é o conjunto de linguagens que são decidı́veis em tempo polinomial por uma MT:
[
NP = N T IM E(nk )
k≥1

Segundo Cormen[1], a classe NP é composta pelos problema que podem ser verificados, aplicando-se uma
algoritmo de verificação, em tempo polinomial.

Embora, como dito anteriormente, P ⊆ NP, existe entre os cientistas da computação uma crença de que P
6 NP. Tal crença deriva da existência de uma classe de problemas chamados NP-completos. A classe NP-completo
=
é a classe de problemas de decisão que contém os mais difı́ceis problemas NP, ou seja, todo problema NP-completo
é, também, um problema NP e todo problema NP pode ser reduzido a um problema NP-completo. Esta classe tem
um propriedade intrigante, caso algum problema NP-completo possa ser solucionado em tempo polinomial, então todo
problema em NP tem uma solução em tempo polinomial, o que implicaria em P = NP. No entanto, apesar de muitos
anos de pesquisa e estudo, ninguém foi capaz de descobrir um algoritmo de tempo polinomial capaz de solucionar um
problema NP-completo.

Na figura 1, considerando a crença de que P 6= NP, apresentamos uma representação esquemática dos conjuntos
dos problemas P, NP, NP-completo e NP-hard.

2.4 Classe NP-hard

Ainda segunda Ullman[2], alguns problemas L são tão difı́ceis que não é possı́vel provar todas as condições im-
postas na definição de NP-completude. Estes problemas L são chamados NP-hard. Estes problemas são, informalmente,
referidos como intratáveis, pois parecem requerer tempo exponencial.

3 Trabalhos Relacionados

A literatura sobre as formas de tratar o problema do caixeiro é muito vasta e ativa no campo da computação.
Mohsen[3], em sua pesquisa, apresenta um algoritmo hı́brido chamado de Annealing Ant Colony Optimization with
Mutation Operator, que mescla, sob determinadas condições, a otimização por colônia de formigas (ACO), recozimento
simulado (SA) e operador de mutação. Antes da apresentação da solução proposta por Mohsen, é necessário uma
contextualização sobre as outras abordagens relacionadas ao trabalho.

A ACO é um algoritmo metaheurı́stico, baseado em população, que foi inspirado no comportamento das
formigas buscando pelo circuito mais curto entre a fonte de alimentação e o ninho. De forma análoga, as formigas

4
NP-hard

NP-completo

NP

Figure 1: Conjunto de Problemas

artificiais buscam por boas soluções iterativamente em várias gerações. Em cada geração, cada formina artificial constrói
seu circuito de solução, passo a passo, guiada por uma regra de transição que é uma função do feromônio artificial e
da distância entre duas cidades[12] como mostrado em (7). Em seguida, a formiga deixa um rastro de feromônio em
seu circuito de solução completo. Por sua vez, na próxima geração, as formigas serão atraı́das pela trilha de feromônios
deixada pela geração anterior, o que norteará a busca no espaço de busca.

A seleção de um ponto a ser visitado, na ACO, é determinada pela equação (7). Através dela, é calculada a
probabilidade de, estando no ponto i, o ponto j visitado.
α β
τij ηij
Pijk = P α β
, (7)
j∈Nik τij ηij

onde τij representa a quantidade de feromônio entre os pontos i e j, ηij indica a distância entre os pontos i e j, β é o
parâmetro que significa a importância relativa do feromônio versus o valor heurı́stico, e Nik é o conjunto de pontos que
a formiga k ainda não visitou.

Por sua vez, o recozimento simulado (SA) é uma técnica de otimização baseada em trajetória. Em problemas
combinatórios, seu uso remonta ao anos de 1980 [13, 14]. O SA utiliza uma abordagem iterativa de melhoria de sua
configuração, utilizando um critério que, eventualmente, aceita configurações com custos maiores. A inspiração para o
desenvolvimento deste algoritmo advém da fı́sico-quı́mica, mais especificamente do processo de recozimento de metais,
que consiste em aquecer um metal e resfriá-lo lentamente até que atinja um estado de menor energia. Neste procedimento,
o metal passa por alterações que lhe proporcionam a aquisição de novas caracterı́sticas.

No SA, um configuração é sempre aceita caso apresente uma variação negativa de energia, ou seja, a partir de
uma configuração de maior custo alcançar uma de menor custo. No entanto, caso a variação de energia seja positiva, ou
seja, a partir de uma configuração de menor custo atingir um de maior custo, a nova configuração será aceita com um
probabilidade dada pelo fator de Boltzmann, mostrado na equação 8, evitando que o algoritmo fique preso em um ponto
ótimo local.

exp−∆custo/temperatura (8)

A iteração, numa dada temperatura, é repetida até que se tenha uma amostra estatı́stica razoável. Posterior-
mente, a temperatura é reduzida e a iteração novamente repetida até que um estado sem energia seja alcançado, ou seja,
quando temperatura = 0.

Por sua vez, operador de mutação foi inspirado nos algoritmos evolucionários. Neles, cada elemento da pop-
ulação terá uma probabilidade predefinida de sofrer uma alteração (mutação), levando o elemento a apresentar uma nova
configuração que não será muito diferente da original.

5
Para Mohsen[5], a justificativa para adoção de uma abordagem hı́brida ocorre pelo fato de, na aplicação
isolada de um algoritmo metaheurı́stico, neste caso o ACO, existir a possibilidade de perda da diversidade populacional
em decorrência de uma convergência prematura da populução. Como consequência, o algoritmo ficaria preso em um
ótimo local.

Sobre o uso de ACO hı́bridos, os primeiros estudos foram conduzidos por McKendall e Shan[4], apresentando
um ACO hı́brido para solucionar o problema de layout de instalação dinâmica. Muitos outras pesquisas sobre ACO
hı́bridos surgiram posteriormente, cabendo destacar os trabalhos realizados por Huang e Liao[6], Yoshikawa e Otani[7],
Xing et al.[8], Liao et al.[9], Lin et al.[10], Hajipour et al.[11], e Min et al.[5].

Para a solução do problema do caixeiro viajante, Mohsen propõe a seguinte abordagem:

Passo 1 : Feita a configuração inicial, cada formiga construirá seu próprio circuito aplicando as regras de
transição e as regras de atualização local do feromônio.

Passo 2 : Calcular o custo do circuito de cada formiga. Em seguida, aplicar a regra de atualização global dos
feromônios, na qual um quantidade maior de feromônio é adicionada ao melhor circuito.

Passo 3 : Calcular a diversidade da população. Caso a diversidade esteja alta, o algoritmo necessita de in-
tensificação pela aplicação de SA. Por outro lado, caso a diversidade esteja baixa, o algoritmo necessita aumentar a
diversidade da população através da aplicação de operador de mutação.

Passo 4 : Aplicar um procedimento de busca local para melhorias adicionas.

Passo 5 : Aplicar, novamente, a atualização global dos feromônios.

Passo 6 : Caso a condição de encerramento tenha sido atingida, retornar o melhor circuı́to encontrado. Do
contrário, retornar ao passo 1.

Em sua pesquisa, Mohsen apresenta resultados comparativos com outros algoritmos considerados estado da
arte para a solução do problema do caixeiro viajante. Dentre eles, cabem destacar Chen e Chien [17], Wang et al.[18],
Yousefikhoshbakht et al.[16], e Mahi et al.[15].

Comparativamente, o algoritmo proposto por Mohsen, em todas as simulações apresentadas em seu estudo,
encontra soluções tão boas quanto ou melhores que aquelas apresentadas pelos algoritmos proposto por Chen e Chien,
Wang et al., Yousefikhoshbakht et al., Mahi et al. e a versão elitista da ACO, em todas as entradas utilizadas. Inclusive,
a média do custo e o desvio padrão apresentam valores menores que aqueles apresentados pelos demais algoritmos, o que
indica que o novo algoritmo proposto tem uma melhor estratégia para a geração das configurações.

Quanto ao número de iterações necessárias para atingir a condição de parada, ou seja, alcançar o menor circuito
conhecido, quando comparado à versão elitista da ACO, em 79, 16% das entradas o novo algoritmo termina sua execução
com 11 (onze) ou menos iterações. Por sua vez, nas simulações realizadas, a ACO elitista, mesmo após realizar 999
iterações, não conseguiu atingir a menor rota conhecida.

No quesito tempo de execução, cabe destacar a seguinte observação. Em 70, 83% das entradas, o novo algoritmo
apresentou tempo de execução inferior ao da ACO elitista. Neste ponto, cabe frisar que em todas as simulações a ACO
passou por 999 iterações, o que nem sempre ocorreu com o novo algoritmo. Em 20, 83% dos casos, o novo algoritmo não
encontrou o melhor circuito conhecido, o que o levou a atingir o limite de 999 iterações. Nesta situação, em 80% das
entradas, o novo algoritmo teve tempo execução, em média, 3.8 vezes maior que o ACO, e com uma redução do custo
do circuı́to, em média, de 8, 75%. Estes números mostram que uma iteração do novo algoritmo tenda a ser mais custosa
do uma iteração no ACO.

Quando efetuamos comparação semelhante, desta vez usando como benchmark os algoritmo proposto por Chen
e Chien e Wang et al., o resultados apresentam alteração. Em 50% das entradas o novo algoritmo apresenta melhor
resultado que do pelo menos um dos outros algorı́timos e em 25% das entradas apresenta resultado melhor do que ambos
os algoritmos. A redução média do custo do circuı́to, neste comparativo, foi de 0.8%. Neste comparativo, o trabalho não
disponibiliza dados referentes ao número de iterações realizadas ou o tempo gasto para a geração do resultado.

O algoritmo proposto por Mohsen, sem dúvida, apresenta melhorias no que diz respeito ao fato de encontrar
melhores rotas em um tempo aceitável para o problema do caixeiro viajante. Sua solução, em todos as simulações,
encontrou rotas melhores ou tão boas quanto àquelas encontradas pelos algoritmos ditos estado da arte. No entanto,

6
quanto ao tempo de execução e número de iterações, não foi possı́vel realizar comparações com os algoritmos propostos
por Chen e Chien, Wang et al., Yousefikhoshbakht et al. e Mahi et al. Fato que impossibilitou mensurar o custo de
tempo necessário para atingir a melhoria apresentada.

Um ponto do trabalho de Mohsen que pode ser estendido em pesquisas futuras é quanto ao detalhamento da
quantidade necessária de tempo, se maior ou menor, que varia de acordo com a entrada, para a obtenção da redução de
custo observada, em média 0.8%.

4 Metodologia

4.1 Abordagem ingênua

Inicialmente, será proposta uma abordagem ingênua, baseada em busca exaustiva, para a solução do problema
enfrentado pelo FlyFood. Embora esta abordagem disponibilize um resultado ótimo, ou seja, sempre encontrará o circuito
que possui a menor distância possı́vel, seu espaço de busca cresce fatorialmente em função do tamanho da entrada. Este
crescimento fatorial faz instâncias minúsculas do problema necessitarem de um tempo de computação extremamente
elevado. Por exemplo, para uma entrada contendo 14 pontos, o tempo necessário para encontrar a melhor solução será
de, aproximadamente, 24 horas5 , o que torna, consequentemente, seu uso inviável para solucionar problemas reais.

Nesta abordagem, para encontrar o melhor circuito possı́vel, são gerados todos os n!/2 possı́veis circuitos, sendo
n o número de cidades a serem visitadas, exceto o ponto de partida. A escolha desta formulação parte da premissa de que
circuitos inversos ([a, b, c] versus [c, b, a]) representam o mesmo circuito. Objetivando implementar tal comportamento,
necessitamos separar o algoritmo em duas partes. A primeira delas, o algoritmo 1 faz uma combinação 2 a 2 dos pontos
a serem visitados, sendo os pares formados nesta combinação os elementos extremos do circuito a ser percorrido.

Analisando com mais detalhes o algoritmo 1, nele definimos a função Gera circuito sem inverso, que recebe
como argumento uma lista chamada visitas que contem todas os pontos a serem visitados, exceto o próprio ponto de
partida/chegada e retorna uma lista contendo todos as possı́veis rotas que podem ser criadas a partir da lista visitas.

Inicialmente, alocamos na memória a lista chamada circuitos que receberá todos os circuitos que podem ser
gerados. Em seguida, é feita uma checagem da quantidade de pontos a serem visitados (TAMANHO(visitas) < 3). Caso
seja inferior a três pontos, ou seja, não existe a quantidade mı́nima de pontos para geração de circuitos distintos, a função
5 Considerando a execução do algoritmo 1 em um computador AMD Ryzen 5 2600 3.4GHz

7
armazenará uma cópia da lista visitas em circuitos, sendo esta a única rota a ser gerada.

Algorithm 1: Gerador de circuitos não inversos


input : visitas - lista de pontos a serem visitados
output: uma lista contendo todos os circuitos válidos
Function Gera circuito sem inverso(visitas)
circutos ← lista inicialmente vazia, que armazena os circuitos;
if TAMANHO(visitas) menor que 3 then
ADICIONAR(circutos, CÓPIA(visitas))
else
caminho ← lista de TAMANHO(visitas) elementos;
for i ← 1 to TAMANHO(visitas) - 1 do
circuito[1] ← visitas[i];
for j ← i + 1 to TAMANHO(visitas) do
circuito[TAMANHO(visitas)] ← visitas[j];
visitas restantes ← CÓPIA(visitas);
REMOVER(visitas restantes, visitas[i]);
REMOVER(visitas restantes, visitas[j]);
Gera cicuitos(circuitos, visitas restantes, caminho, 2)
end
end
end
return circuitos;
end

Existindo a quantidade de pontos suficientes, ou seja, o tamanho de visitas é, pelo menos, igual a 3, alocaremos
na memória o espaço para criação do circuito. Posteriormente, navegaremos através dos pontos existentes em visitas
para a geração das combinações 2 a 2 que formarão os elementos extremos do circuito.

Atribuı́do os elementos extremos, ou seja, o primeiro elemento de circuito recebe o i-ésimo ponto de visitas e
o último elemento de circuito recebe o j-ésimo ponto de visitas, precisaremos alocar espaço para armazenar os pontos
ainda não visitados. Esta alocação é realizada através de visitas restantes, que recebe uma cópia de visitas. No entanto,
como já foram definidas as posições de dois pontos do circuito (i e j), é necessário remover de visitas restantes estes
elementos. Na sequência, será delegada à função definida no algoritmo 2 o papel de preencher os caminhos que poderão
ser criados após fixados os pontos extremos do circuito.

Encerrada a formação das combinações de todos os elementos extremos, bem como formadas todas as per-
mutações dos pontos localizados entre eles, será retornado ao usuário a lista circuitos, contendo todos os possı́veis
circuı́tos válidos para os pontos dados.

No algoritmo 2, é definida a função Gera circuitos, que recebe como argumentos uma lista chamada circuitos,
na qual são armazenados os circuitos válidos gerados, uma lista visitas contendo os pontos a serem visitados, uma lista
caminho contendo uma lista parcialmente preenchida, que representa o circuito a ser percorrido, e um inteiro posicao que
indica qual a próxima posição de caminho a ser preenchida. Cabe destacar que esta função apenas manipula os valores
de circuitos e de caminho, não havendo o retorno de um valor durante a sua execução.

Iniciada a execução de Gera circuitos, é feita uma checagem da quantidade de pontos a serem visitados. Caso
não existam pontos a serem visitados, ou seja, o tamanho de vistas é igual a 0, uma cópia de caminho é adicionada
à circuitos. Caso exista algum elemento em visita, é necessário navegar por todos os seus elementos. Cada elemento
será adicionado, um a um, em caminho, o valor e posicao precisará ser incrementado, o elemento adicionado deverá ser
removido de uma cópia da lista visitas e, por fim, a função Gera circuitos é chamada recursivamente até que o caso base

8
(A, B, C)
(, , )
1
1 6 11
(B, C) (A, C) (A, B)
(A, , ) (B, , ) (C, , )
2 2 2
2 4 7 9 12 14
(C) (B) (C) (A) (B) (A)
(A, B, ) (A, C, ) (B, A, ) (B, C, ) (C, A, ) (C, B, )
3 3 3 3 3 3
3 5 8 10 13 15
() () () () () ()
(A, B, C) (A, C, B) (B, A, C) (B, C, A) (C, A, B) (C, B, A)
4 4 4 4 4 4

Figure 2: Árvore de execução das chamadas recursivas

seja atingido.

Algorithm 2: Gerador de circuitos


input : circuitos - lista que armazena os caminhos gerados
visitas - lista de pontos a serem visitados
caminho - lista que representa o caminho a ser percorrido
posicao - próximo elemento do caminho a ser preenchido
Function Gera circuitos(circuitos, visitas, caminho, posicao)
if TAMANHO(visitas) é igual a 0 then
ADICIONAR(circuitos, CÓPIA(caminho))
else
for i ← 1 to TAMANHO(visitas) do
circuito[position] ← visitas[i];
visitas restantes ← CÓPIA(visitas);
REMOVER(visitas restantes, visitas[i]);
Gera circuitos(visitas restantes, circuito, posicao + 1);
end
end
end

A figura 2 ilustra a sequência de chamadas recursivas da função Gera circuitos para geração dos caminhos
possı́veis para um entrada de tamanho 3, contendo os elementos (A, B, C). Para manter a simplicidade do exemplo, os
nós não mostrarão os valores armazenados na lista circuitos. Como era de se esperar, a árvore presenta 6 folhas, cada um
presentando um dos 3! possı́veis circuitos a serem formados. Ainda quanto às folhas, é possı́vel observa que cada uma
atingiu a condição de parada do algoritmo recursivo - a lista visitas está vazia. Os números ao lado das arestas indicam
a sequência de execução das chamadas recursivas.

Calculados todos os possı́veis circuitos, faz-se necessário calcular o custo de cada um deles objetivando encontrar
aquele que apresenta o menor custo. O cálculo do custo é obtido através do algoritmo 3. Neste algoritmo, observamos que
é calculada a DIST AN CIA entre os pontos i e i + 1 da lista caminho, sendo o valor acumulado na variável custo total, a
qual foi inicializada previamente como valor 0. Por fim, é necessário calcular e somar à variável custo total as distâncias
entre origem e o primeiro e o último elementos de caminho. Por fim, o valor do custo total do circuito é retornado pela
função.

Por fim, sendo possı́vel calcular o custo de um circuito, é necessário encontrar aquele com o melhor custo. Este

9
procedimento é executado pelo algoritmo 4. Neste algoritmo, inicializamos as variáveis melhor custo e melhor caminho,
respectivamente, com os valores + inf e NULL. Em seguida, geramos todos os circuitos possı́veis ao executarmos a função
Gera circuito sem inverso, sendo a lista de circuitos armazenada em caminhos. Por fim, é necessário navegar por
todos os circuitos gerados e calcular seu custo através da função Distancia circuito. Caso o custo de um circuito i, que
é armazenado na variável distancia, seja menor do que melhor custo, então melhor custo receberá o valor de distancia
e melhor caminho armazenará o circuito i.

Algorithm 3: Cálculo do custo de um determinado caminho


input : origem - ponto de partida/chegada do circuito
caminho - lista contendo a sequência de visitas
output: o custo total do circuı́to
Function Distancia circuito(origem, caminho)
custo total ← 0;
for i ← 1 to TAMANHO(caminho) - 1 do
distancia ← DISTANCIA(caminho[i], caminho[i + 1]);
custo total ← custo total + distancia;
end
distancia ← DISTANCIA(origem, caminho[1]);
custo total ← custo total + distancia;
distancia ← DISTANCIA(caminho[TAMANHO(caminho)], origem);
custo total ← custo total + distancia;
return custo total;
end

Algorithm 4: Encontra o caminho com menor custo


input : origem - ponto de partida/chegada do circuito
visitas - lista contendo os pontos a serem visitados
output: o caminho com o menor custo
Function Melhor circuito(origem, visitas)
melhor custo ← +∞;
melhor caminho ← NULL;
caminhos ← Gera circuito sem inverso(visitas);
for i ← 1 to TAMANHO(caminhos) do
distancia ← Distancia circuito(origem, caminhos[i]);
if distancia < melhor custo then
melhor custo ← distancia;
melhor caminho ← caminhos[i];
end
end
return melhor caminho;
end

Após navegar por todo caminho existente em caminhos, o algoritmo 4, retornar o circuito que apresenta o
menor custo dentre todos os circuitos existentes.

4.2 Algoritmos Genéticos

Considerando a intratabilidade inerente ao problema do caixeiro viajante, dado que seu espaço de busca cresce
fatorialmente em relação ao tamanho da entrada, outras técnicas - as chamadas metaheurı́sticas - se fazem necessárias
para solucioná-lo.

Uma das metaheurı́sticas utilizadas para se encontrar uma solução suficientemente boa em um tempo aceitável
são os Algoritmos Genéticos - AG. Segundo Russell e Norvig[19], os AG’s são uma variante de busca em feixe estocástica,
na qual os novos estados são formados pelo cruzamento de dois estados pais. Como o próprio nome pode sugerir, os
algoritmos genéticos pertencem à classe dos chamados algoritmos evolutivos, os quais, inspirados na biologia, trazem para
a computação conceitos como hereditariedade, mutação, seleção, recombinação, etc. A figura 3 apresenta o fluxograma
de um AG genérico.

10
Inı́cio

População Inicial

Calcular fitness

Seleção

Cruzamento

Mutação

não
Finalizar?

sim
Fim

Figure 3: Fluxograma de um Algoritmo Genético

A inicialização de uma AG ocorre com a criação de uma população inicial. Em seguida, é preciso calcular o
fitness de cada um dos elementos da população para aferição da aptidão, ou seja, verificar o quão boa é a solução contida
naquele indivı́duo.

O passo seguinte é a seleção dos indivı́duos. Nesta fase, considerando os valores de fitness através de algum
critério, serão escolhidos os indivı́duos que passarão pelo processo de cruzamento e darão origem aos novos elementos da
próxima geração. Efetuado o cruzamento, os novos elementos gerados passarão pelo processo de mutação.

Por fim, formada a nova população é preciso decidir, com base em um critério de parada, se uma nova geração
de indivı́duos será necessária, reiniciando o ciclo, ou se a busca foi encerrada.

Sendo o Flyfood, como já mencionado anteriormente, uma instância do problema do caixeiro viajante, a solução
proposta para viabilizar a manipulação de entradas maiores - conjunto de pontos de entrega maior - fará uso de algoritmos
genéticos, cujas caracterı́sticas serão descritas nas seções subsequentes.

4.2.1 População Inicial

A população inicial será formada por n elementos, sendo n o tamanho da população desejada. Ademais,
cada elemento consiste de uma permutação aleatória dos pontos de entrega que precisam ser visitados6 . O algoritmo 5
6 Paralelamente, outra abordagem para formação da população inicial foi implementada, fazendo uso da Heurı́stica de Bellmore

e Nemhauser. Embora apresente resultados iniciais melhores, para viabilizar a visualização do funcionamento do AG, ela não será
adotada.

11
apresenta o pseudocódigo para geração da população inicial.

Algorithm 5: Gera a população inicial


input : pontos - lista contendo os pontos de entrega a serem visitados
n - quantidade de indivı́duos da população
output: Uma população inicial de tamanho n
Function Populacao inicial(pontos, n)
populacao; (um array de tamanho n)
for i ← 1 to n do
individuo ← PERMUTACAO ALEATORIA(pontos);
ADICIONAR(populacao, individuo);
end
return populacao;
end

4.2.2 Fitness

A função de fitness utilizada é baseada no custo do circuito, conforme algoritmo 3 e equação 4. Cabe destacar,
ainda, a necessidade de pequenas adaptações para uso desta função quando, na seleção, for utilizado o método da roleta
ou por ranking linear. Uma vez que o melhor Fitness pertence ao indivı́duo que apresenta ou a menor distância ou a
melhor (e menor em valor absoluto) posição no ranking.

4.2.3 Seleção

No FlyFood, será utilizada a técnica de seleção por torneio. Serão selecionados, aleatoriamente, k elementos
da população e o mais apto, ou seja, aquele que possui o circuito mais curto, será selecionado. O algoritmo 6 apresenta
o pseudocódigo do método por torneio.

Algorithm 6: Seleção por torneio


input : populacao - população que fornecerá os indivı́duos a serem selecionados
k - quantidade de indivı́duos selecionados no torneio
output: o indivı́duo mais apto dentre os selecionados
Function torneio(populacao, k)
selecionados ← ESCOLHA ALEATORIA(populacao, k);
mais apto ← min(selecionados);
return mais apto;
end

4.2.4 Cruzamento

O método de cruzamento adotado será o Partially-Mapped Crossover (PMX), introduzido por Goldberg and
Lingle[21], com 1 ponto de crossover. O PMX, com 1 ponto de crossover, apresenta o seguinte funcionamento, dados dois
pais quaisquer, p1 e p2, para a geração de um dos filhos:

(a) Selecionar, ao acaso, o ponto de crossover (p);


(b) Criar uma cópia de p2 (cp2);
(c) Copiar p1[1..p] para cp2[1..p]. No entanto, como é preciso manter o circuito válido, não basta efetuar a substituição
dos valores. É necessário, em cp2, localizar a posição na qual o novo valor se encontra para efetuar sua troca de
posição com o valor que será substituı́do.

A figura 4, apresenta um exemplo do PMX em funcionamento, tendo como pais as sequências (3, 1, 5, 8, 9, 4,
6, 2, 7) e (4, 1, 9, 7, 8, 2, 6, 5, 3). O algoritmo 7, por sua vez, apresenta o pseudocódigo do PMX. Importante destacar

12
3 1 5 8 9 4 6 2 7 4 1 5 8 9 3 6 2 7 4 1 9 8 5 3 6 2 7

4 1 9 7 8 2 6 5 3 4 1 9 7 8 2 6 5 3 4 1 9 7 8 2 6 5 3

Filho 1: 4 1 9 7 5 3 6 2 8

3 1 5 8 9 4 6 2 7 3 1 5 8 9 4 6 2 7 3 1 5 8 9 4 6 2 7

4 1 9 7 8 2 6 5 3 3 1 9 7 8 2 6 5 4 3 1 5 7 8 2 6 9 4

Filho 2: 3 1 5 8 7 2 6 9 4

Figure 4: Exemplo da aplicação do PMX

que o crossover terá sua execução condicionada a uma probabilidade e, caso esta não seja atingida, uma cópia de cada
pai será utilizada como novo indivı́duo.

Algorithm 7: PMX
input : pai1, pai2 - elementos que fornecerão os cromossomos para os novos indivı́duos
output: tupla contendo 2 indivı́duos gerados pelo cruzamento
Function PMX(pai1, pai2)
resultado; (2-tupla)
pai ← pai1;
copia ← COPIA(pai2);
ponto cruzamento ← número randômico entre 1 e TAMANHO(pai);
for k ← 1 to 2 do
for i ← 1 to ponto cruzamento do
if copia[i] != pai[i] then
temp ← copia[i];
copia[i] = pai[i];
for j ← i + 1 to TAMANHO(copia) do
if copia[i] = copia[j] then
copia[j] ← temp;
break;
end
end
end
end
resultado[k] ← copia;
pai ← pai2;
copia ← COPIA(pai1);
end
return resultado;
end

4.2.5 Mutação

A última etapa no processo de geração de novos indivı́duos em um algoritmo genético é a mutação. Nesta fase,
serão experimentados dois métodos distintos. No primeiro deles, chamado Partial Shuffle Mutation - PSM, com base em
uma probabilidade, será decidido, para cada um dos alelos do cromossomo que representa a solução, se ocorrerá ou não
mutação. No segundo método, chamado de Reverse Sequence Mutation - RSM, serão escolhidos dois número aleatórios
compreendidos 1 e o tamanho do cromossomo. Em seguida, o trecho do cromossomo compreendido entres estes números

13
i1 j1 i7 j7

3 1 5 8 9 4 6 2 7 4 1 5 8 9 3 7 2 6

Figure 5: PSM - Apenas nas posições 1 e 7 a probabilidade foi atingida.

a b

3 1 5 8 9 4 6 2 7 3 1 4 9 8 5 6 2 7

Figure 6: RSM - Valores atribuı́dos: a = 3 e b = 6.

terá sua sequência invertida.

Algorithm 8: Partial Shuffle Mutation - PSM


input : individuo - sequência que irá sofrer a mutação
probabilidade - probabilidade de ocorrer a mutação
output: indivı́duo contendo a sequência após a mutação
Function PSM(individuo, probabilidade)
for i ← 1 to TAMANHO(individuo) do
pi ← número aleatório entre 0 e 1;
if pi ≤ probabilidade then
j ← número aleatório entre 1 e TAMANHO(individuo);
PERMUTAR(individuo[i], individuo[j]);
end
end
end

Algorithm 9: Reverse Sequence Mutation - RSM


input : individuo - sequência que irá sofrer a mutação
output: indivı́duo contendo a sequência após a mutação
Function RSM(individuo)
Escolher 2 pontos de crossover a e b tal que 1 ≤ a ≤ b ≤ T AM AN HO(individuo)
while a < b do
PERMUTAR(individuo[a], individuo[b]);
a ← a + 1;
b ← b - 1;
end
end

O algoritmo 8 e a figura 5 apresentam, respectivamente, o pseudocódigo e um exemplo do PSM. Por sua vez,
o algoritmo 9 a figura 6 apresentam, respectivamente, o pseudocódigo e um exemplo do RSM.

4.2.6 Critério de Parada

Dois critérios de parada foram implementados para o FlyFood. O primeiro deles baseado no número de
gerações que devem ser computadas, ou seja, após k gerações, a execução do algoritmo genético será finalizada. O
segundo é baseado na quantidade de vezes em que não há alteração do melhor indivı́duo presente na população, ou seja,
após n gerações consecutivas sem que um indivı́duo mais apto seja encontrado, o algoritmo será finalizado.

4.2.7 Próxima Geração e Parâmetros

Os resultados apresentados neste trabalho utilizarão elitismo na formação das gerações subsequentes. Para a
análise comparativa entre o uso dos operadores de mutação PMS e RSM, serão utilizados os seguintes parâmetros:

14
(a) Tamanho da população: 200 indivı́duos
(b) Taxa de elitismo: 15% (30 indivı́duos)
(c) Probabilidade de crossover: 80%
(d) Probabilidade de mutação: 1%
(e) Seleção: por torneio (k = 2)
(f) Cruzamento: PMX
(g) Critério de parada: quantidade de gerações (20.000)

Outra análise, terá por base os parâmetros acima elencados, exceto pelas seguintes alterações:

(a) Probabilidade de mutação: 25% para RSM e 0,1% para PSM7 .


(b) Critério de parada: 100 gerações sem alteração do melhor indivı́duo

5 Experimentos

5.1 Abordagem ingênua

Para implementação dos algoritmos, realizada na linguagem Python, foram utilizados generators, o que implica
em pequenas diferenças quando comparados ao pseudocódigo. A opção por generators proporcionará economia de
memória, visto que cada caminho válido poderá ter seu custo avaliado no momento em que for finalizada a sua criação.
Não sendo necessário o armazenamento em memória de todos os caminhos antecipadamente.

Como esperado, embora forneça soluções ótimas, a busca exaustiva se mostrou impraticável para entradas
acima de 14 pontos (1 origem + 13 pontos de entrega). Para permutação sem circuı́tos inversos dos locais de entrega, os
experimentos8 apontaram os tempos de execução mostrados na tabela 1.

Entrada Tempo
2 0.000057 s
3 0.000142 s
4 0.000534 s
5 0.001510 s
6 0.003867 s
7 0.047474 s
8 0.099958 s
9 0.888257 s
10 9.059275 s
11 1 min e 41.434492 s
12 20 min e 59.933144 s
13 4 h, 40 min e 27.891443 s

Table 1: Tempo de execução verificado

Conforme a figura 7(a), o tempo de execução descrito na tabela 1 apresenta um crescimento súbito quando
a entrada varia de 12 para 13 locais visitados. Considerando que o espaço de busca varia fatorialmente em relação ao
tamanho da entrada, o que justifica tal comportamento, é possı́vel estabelecer uma função 9, que se aproxima dos tempos
de execução do experimento9,10 . Caso adicionemos a curva gerada pela função 9 ao gráfico da figura 7(a), observaremos
7 Foi
adotado o valor de 0,1% uma vez que probabilidades elevadas no PSM pioram a qualidade das soluções apresentadas.
8 Considerando a execução do algoritmo 1 em um computador AMD Ryzen 5 2600 3.4GHz.
9 Para os experimentos realizados, na ferramenta SageMath 9.2, o valor encontrado para c foi 2.701967902460184e−6 .
10 Cabe frisar que a função fatorial está restrita aos conjunto dos números inteiros. Para a geração dos pontos do gráfico, foi

utilizada a função gamma, que é uma extensão da função fatorial para os números complexos.

15
(a) Tempo de execução verificado (b) Função de aproximação do tempo de execução

Figure 7: Análise do tempo de execução

a coincidência entre pontos e curva, conforme figura 7(b). A partir da função 9, é possı́vel estimar o tempo de execução
para diversos tamanhos de entrada, conforme tabela 2.

f (n) = c.n! (9)

sendo c uma constante e n o tamanho da entrada.

Entrada Tempo
5 0.000324 s
6 0.001945 s
7 0.013618 s
8 0.108943 s
9 0.980490 s
10 9.804901 s
11 1 min, 47.853912 s
12 21 min
13 4 h, 40 min
14 2 d, 17 h, 25 min
15 1 m, 10 d, 21 h
16 1 a, 9 m, 19 d
17 30 a, 5 m, 23 d
18 548 a, 6 m, 20 d
19 10.422 a
20 208.448 a

Table 2: Tempo de execução estimado

Como pode ser observado na tabela 2, a partir de 14 entradas, o uso da abordagem ingênua se torna inviável,
necessitando de aproximadamente 3 dias de execução para apresentar um resultado. Se ampliarmos o tamanho da entrada
para 20, seriam necessários, aproximadamente, 208 mil anos de tempo de execução para apresentação do resultado.

Embora seu uso em aplicações reais não seja viável, como já mencionando anteriormente, o resultado apresen-
tado por esta abordagem, baseada numa busca exaustiva, apresenta sempre o melhor resultado possı́vel. A seguir, para
um pequeno exemplo, mostraremos o resultado obtido pelo algoritmo.

Matriz de entrada, no formato (10, 10):

16
Ponto Coordenada
-1 (3, 5)
1 (0, 0)
2 (7, 7)
3 (1, 6)
4 (1, 1)
5 (9, 8)
6 (4, 5)
7 (3, 2)
8 (4, 1)
9 (7, 4)
10 (5, 3)
11 (2, 7)
12 (6, 7)

Figure 8: Pontos de entrega no plano Table 3: Pontos da matriz 10


1 0 0 0 0 0 0 0 0 0

0 4 0 0 0 0 3 0 0 0

0 0 0 0 0 0 0 11 0 0

0
0 7 0 0 −1 0 0 0 0
0 8 0 0 0 6 0 0 0 0

0 (10)
0 0 10 0 0 0 0 0 0
0 0 0 0 0 0 0 12 0 0

0 0 0 0 9 0 0 2 0 0

0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0 5 0

Na matriz 10, os pontos de interesse apresentam as coordenadas apresentadas na tabela 311 :

A partir da tabela 3, podemos representar os pontos em um plano 8. O ponto vermelho indica o ponto de
partida/chegada do circuı́to.

Executado o algoritmo, o melhor circuı́to apresentado é (11, 3, 1, 4, 7, 8, 10, 9, 5, 2, 12, 6), que possui custo
de 30,8 unidades. A figura 9(a) ilustra o trajeto a ser percorrido no melhor circuı́to. Por outro lado, como ilustrado na
figura 9(b), o pior trajeto possui custo de 84,7 unidades e segue a sequência (9, 3, 10, 11, 8, 6, 7, 12, 4, 2, 1, 5).

5.2 Algoritmo Genético

Para implementação dos algoritmos, novamente, foi utilizada a linguagem Python. Para permitir a visualização
em gráfica, foram armazenados os dados referentes ao fitness do melhor e pior circuitos, bem como a média, para
cada geração. Adicionalmente, a cada 5000 gerações, além da primeira e última geração, foi armazenada a sequência
que representa o melhor caminho para se ter uma noção visual do circuito gerado no decorrer do tempo. Todos os
experimentos foram executados utilizando como entrada a instância a280, que contem 280 pontos, do TSPLIB12 , cujo
melhor circuito apresenta distância de 2579 unidades.

5.2.1 Experimento 1

Neste experimento, considerando uma população de 200 indivı́duos, com elitismo à taxa de 15% (30 indivı́duos),
probabilidade de crossover de 80% e de mutação de 1%, com o algoritmo sendo finalizado após 20.000 gerações, utilizando o
11 Como Pyhton é uma linguagem indexada a zero, os ı́ndices de linhas e colunas podem apresentar o valor zero.
12 Disponı́velem http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/tsp/

17
(a) Melhor circuı́to (b) Pior circuı́to

Figure 9: Comparativo de circuı́tos

operador de mutação PSM, o algoritmo necessitou de 13 minutos e 19 segundos para concluir sua execução. Ao término,
foi apresentado um caminho com custo de 7.957 unidades, cujo surgimento ocorreu na geração 19.960. A figura 10
apresenta a evolução dos melhores circuitos durante a execução do algoritmo. A figura 11 apresenta a evolução, a cada
1000 gerações, dos valores mı́nimo, máximo e médio dos circuitos.

Por outro lado, executando-se novamente o experimento, mas sendo alterado o operador de mutação para RSM,
o algoritmo necessitou de 18 minutos e 23 segundos finalizar sua operação. Ao final, foi apresentado um caminho com
custo de 3.023 unidades, cujo surgimento ocorreu na geração 19.126. A figura 12 apresenta a evolução dos melhores
circuitos durante a execução do algoritmo. A figura 13 apresenta a evolução, a cada 1000 gerações, dos valores mı́nimo,
máximo e médio dos circuitos.

Analisando os gráficos das figuras 11 e 13, fica evidente que o método RSM é o mais adequado para o problema
proposto, visto que convergência da população ocorre de forma rápida e ao mesmo tempo em que se aproxima do melhor
circuito possı́vel, distando deste apenas 444 unidades (17,22% maior). Comparativamente, o PSM, na geração 20.000,
ainda apresenta uma variabilidade muito grande entre os indivı́duos da população, considerando a diferença entre os
valores máximo, mı́nimo e médio. Ademais, o PSM, não se aproximou tão rapidamente do melhor circuito, tendo, para
o número de geração estipulado, retornado um circuito maior do que o melhor em 5.378 unidades (208,5% maior).

Nas figuras 10 e 12, também fica evidente a análise realizada anteriormente. Conforme pode ser observado,
a partir da geração 5.000, o RSM entrega um circuito com menos cruzamentos e, consequentemente, que melhor se
aproxima do circuito ótimo.

5.2.2 Experimento 2

Neste experimento, foram mantidos os mesmo parâmetros utilizados na seção anterior, exceto a taxa de mutação
(25% para o RSM e 1% para o PSM) e o critério de parada (100 gerações sem o surgimento de um indivı́duo mais apto).
Conforme figura 15, novamente o RSM fornece a melhor solução, cujo custo é de 3.364 unidades, 30,44% maior que o
melhor circuito conhecido para a entrada a280. O critério de parada é alcançado na geração 3.065, necessitando de 2
minutos e 49 segundos para ser finalizada.

Por sua vez, ao ser utilizado os PSM, o custo da melhor solução sobe para 7.175 unidades, 178,21% maior que
o melhor circuito conhecido. O critério de parada é alcançado na geração 3.629, com tempo de execução de 1 minuto e
59 segundos.

Por fim, a figura 14 novamente dá destaque à qualidade da solução encontrada usando o RSM, dado o número
reduzido de cruzamentos quando comparado à solução final apresentada quando utilizado o PSM.

18
(a) Geração Inicial (b) Geração 5.000

(c) Geração 10.000 (d) Geração 15.000

(e) Geração 20.000

Figure 10: Evolução dos melhores circuitos gerados utilizando o PSM

Figure 11: PSM - Evolução do valor mı́nimo, máximo e média

19
(a) Geração Inicial (b) Geração 5.000

(c) Geração 10.000 (d) Geração 15.000

(e) Geração 20.000

Figure 12: Evolução dos melhores circuitos gerados utilizando o RSM

20
Figure 13: RSM - Evolução do valor mı́nimo, máximo e média

5.2.3 Análise dos Experimentos

No quesito tempo, considerando que no PSM há a escolha de 2 indivı́duos de forma aleatória, o que é feito em
tempo constante (O(1)), sua execução acaba sendo mais rápida, até mesmo quando produz um número maior de gerações,
como pôde ser visto nos experimentos. Por outro lado, no RSM, o custo adicional de tempo pode ser explicada pela
necessidade de ser feita uma inversão num trecho da rota o que, no pior caso, pode exigir que o tempo varie linearmente
no tamanho da entrada (O(n)).

Considerando as caracterı́sticas do problema, o RSM se mostra mais adequado ao FlyFood, uma instância
do problema do caixeiro viajante, visto que preservar as boas sequências formadas nos cromossomos dos indivı́duos da
população. No PSM, como as trocas ocorrem entre pares aleatórios, as boas sequências existentes nos cromossomos
acabam se perdendo mais facilmente, reduzindo o seu desempenho quando aplicado ao FlyFood.

6 Conclusão

Com o uso de Algoritmos Genéticos, uma técnica metaheurı́stica, é possı́vel encontrar uma solução suficien-
temente boa dentro de um intervalo de tempo aceitável, mesmo quando, usando uma busca exaustiva, o tamanho da
entrada inviabiliza a busca pela melhor solução possı́vel.

Utilizando o Experimento 2 como exemplo, nele encontramos uma solução 30,44% maior do que a melhor
conhecida, necessitando de apenas 2 minutos e 49 segundos para obter o resultado. Se, para a mesma entrada, que possui
280 pontos, fossemos utilizar a busca exaustiva, seriam necessários, aproximadamente 1, 4 · 10552 anos para encontrar a
melhor solução possı́vel. Para se ter uma ideia, segundo os cientistas, o universo tem idade aproximada de 1, 4 · 1010
anos. Ou seja, seria necessário um tempo 10542 vezes maior do que o intervalo entre a ocorrência do Big Bang e os dias
atuais para se encontrar o melhor circuito, o que inviabiliza o uso da busca exaustiva.

Por fim, se analisarmos o uso de memória, caso se deseje armazenar todos os caminhos possı́veis para, só
depois, partir em busca do melhor, seria necessária uma lista com, aproximadamente, 1, 67 · 10565 posições. Partindo
deste número, se fizermos a suposição de que é possı́vel codificar uma rota dentro de um único átomo, seriam necessários,
aproximadamente, 1, 67·10565 átomos para armazenar as possı́veis soluções. No entanto, segundo os cientistas, o universo
conhecido só dispõe de algo entre 1078 a 1082 átomos, o que torna a missão novamente impossı́vel.

References
[1] CORMEN, Thomas H. et al. Introduction to algorithms. 3ª Edição. Cambridge, Massachusetts: MIT Press, 2009.
[2] ULLMAN, Jeffrey D.; MOTWANI, Rajeev; HOPCROFT, John E. Introduction to Automata Theory, Languages, and
Computation. 3ª Edição. Boston: Pearson, 2006.

21
(a) PSM - Geração Inicial (b) PSM - Geração Final

(c) RSM - Geração Inicial (d) RSM - Geração Final

Figure 14: Evolução dos melhores circuitos gerados

Figure 15: Evolução do valor mı́nimo, máximo e média

22
[3] MOHSEN, Abdulqader M. Annealing Ant Colony Optimization with Mutation Operator for Solving TSP. Compu-
tational Intelligence and Neuroscience, vol. 2016, Article ID 8932896, 13 pages, 2016.
https://doi.org/10.1155/2016/8932896
[4] A. R. McKendall and J. Shang, “Hybrid ant systems for the dynamic facility layout problem,” Computers & Opera-
tions Research, vol. 33, no. 3, pp. 790–803, 2006.
[5] H. Min, P. Dazhi, and Y. Song, “An improved hybrid ant colony algorithm and its application in solving TSP,” in
Proceedings of the 2014 7th IEEE Joint International Information Technology and Artificial Intelligence Conference
(ITAIC ’14), pp. 423–427, Chongqing, China, December 2014.
[6] K.-L. Huang and C.-J. Liao, “Ant colony optimization combined with taboo search for the job shop scheduling
problem,” Com- puters & Operations Research, vol. 35, no. 4, pp. 1030–1046, 2008.
[7] M. Yoshikawa and K. Otani, “Ant colony optimization routing algorithm with tabu search,” in Proceedings of the
International MultiConference of Engineers and Computer Scientists, vol. 3, pp. 17–19, 2010.
[8] L.-N. Xing, P. Rohlfshagen, Y.-W. Chen, and X. Yao, “A hybrid ant colony optimization algorithm for the extended
capacitated arc routing problem,” IEEE Transactions on Systems, Man, and Cybernetics, Part B: Cybernetics, vol.
41, no. 4, pp. 1110–1123, 2011.
[9] T. W. Liao, R. J. Kuo, and J. T. Hu, “Hybrid ant colony optimization algorithms for mixed discrete-continuous
optimization problems,” Applied Mathematics and Computation, vol. 219, no. 6, pp. 3241–3252, 2012.
[10] Y.-K. Lin, C.-T. Yeh, and P.-S. Huang, “A hybrid ant-tabu algo- rithm for solving a multistate flow network
reliability maximization problem,” Applied Soft Computing Journal, vol. 13, no. 8, pp. 3529–3543, 2013.
[11] V. Hajipour, P. Fattahi, and A. Nobari, “A hybrid ant colony opti- mization algorithm to optimize capacitated
lot-sizing problem,” Journal of Industrial˙ and Systems Engineering, vol. 7, no. 1, pp. 1– 20, 2014.
[12] K. L. Hoffman, M. Padberg, and G. Rinaldi, “Traveling salesman problem,” in Encyclopedia of Operations Research
and Manage- ment Science, pp. 1573–1578, Springer, Berlin, Germany, 2013.
[13] S. Kirkpatrick, C. D. Gelatt, and M. P. Vecchi, “Optimization by simulated annealing,” Science, vol. 220, no. 4598,
pp. 671–680, 1983.
[14] V. Cerny, “Thermodynamical approach to the traveling salesman problem: an efficient simulation algorithm,”
Journal of Optimization Theory and Applications, vol. 45, no. 1, pp. 41–51, 1985.
[15] M. Mahi, O. K. Baykan, and H. Kodaz, “A new hybrid method based on particle swarm optimization, ant colony
optimization and 3-Opt algorithms for traveling salesman problem,” Applied Soft Computing, vol. 30, pp. 484–490,
2015.
[16] M. Yousefikhoshbakht, N. Malekzadeh, and M. Sedighpour, “Solving the traveling salesman problem based on the
genetic reactive bone route algorithm whit ant colony system,” International Journal of Production Management and
Engineering, vol. 4, no. 2, pp. 65–73, 2016.
[17] S.-M. Chen and C.-Y. Chien, “Solving the traveling salesman problem based on the genetic simulated annealing ant
colony system with particle swarm optimization techniques,” Expert Systems with Applications, vol. 38, no. 12, pp.
14439–14450, 2011.
[18] C. Wang, M. Lin, Y. Zhong, and H. Zhang, “Swarm simulated annealing algorithm with knowledge-based sampling
for travelling salesman problem,” International Journal of Intelligent Systems Technologies and Applications, vol. 15,
no. 1, pp. 74–94, 2016.
[19] Russell, Stuart. J.; Russell, Peter Norvig. Inteligência Artificial. Rio de Janeiro: Elsevier, 2004.
[20] Baker, James Edward. ”Adaptive selection methods for genetic algorithms.”Proceedings of an International Confer-
ence on Genetic Algorithms and their applications. 1985.
[21] Goldberg, D.E., and R. Lingle. “Alleles, Loci, and the Traveling Salesman Problem.” Proceedings of the First
International Conference on Genetic Algorithms and Their Application, edited by Grefenstette J., Lawrence Erlbaum
Associates, Hillsdale, NJ, 1985, pp. 154-159.

23

Você também pode gostar