Escolar Documentos
Profissional Documentos
Cultura Documentos
ii
OTIMIZAÇÃO DE ROTAS PARA A COLETA DO LIXO DOMÉSTICO:
UM TRATAMENTO GRASP DO PROBLEMA DO CARTEIRO CHINÊS
MISTO (PCCM)
Comissão Examinadora:
iv
AGRADECIMENTOS
A Deus, o Jeová Shalon (Deus da paz), o grande Jeová Jiré (Deus da provisão),
onde pude buscar forças nos momentos de desânimo e luz nos momentos obscuros.
Toda honra e toda glória sejam dadas ao Príncipe da Paz – Jesus Cristo. Tu és o Rei
da minha vida!
A minha amada mãe que me incentivou por diversas vezes a ingressar no
mestrado levantando minha auto-estima e me dando forças. Se hoje tenho este título,
dedico a você mãe!
A minha amada esposa que soube conduzir por meio da compreensão e
carinho esta caminhada, estando ao meu lado em todos os momentos.
A minha orientadora professora Gudelia, pela amizade, incentivo e,
principalmente, por depositar confiança em mim, acreditando no meu potencial. Muito
obrigado!
Ao professor Geraldo Galdino pelo apoio e a todos os professores do
Laboratório de Engenharia de Produção.
Ao meu grande camarada Leonardo Póvoa, amigo desde os tempos da UERJ.
Suas idéias foram fundamentais para o sucesso deste trabalho. Muito obrigado pela
força!
Aos meus amigos e colegas de mestrado, em especial ao meu bom e velho
amigo André Velasco, e ao grande Eduardo Varejão pela força e ajuda em minhas
dificuldades e aos funcionários do CCT da UENF, pela amizade e apoio.
A FAPERJ pelo apoio financeiro durante o período de mestrado.
E a todos aqueles que, de uma forma ou de outra, contribuíram para a
conclusão deste trabalho.
v
SUMÁRIO
LISTA DE TABELAS............................................................................................... ix
LISTA DE FIGURAS................................................................................................ x
RESUMO.................................................................................................................. xii
ABSTRACT.............................................................................................................. xiii
Capítulo 1 - Introdução......................................................................................... 1
1.1– Considerações Iniciais…………………………………………………......... 1
1.2– Organização da Tese......……………………………………………............ 3
vi
3.1 – O Problema de Roteamento em Arcos… ...… … … … … … … … … ............. 24
3.2 – O Problema do Carteiro Chinês (PCC)… ..… … … … … … … … … ............. 25
3.2.1 – Um Breve Histórico… .......… … … … … … … … … … … … … … … ......... 25
3.2.2 – Algumas Definições Inerentes ao PCCM......… ....… … … ............... 26
3.2.3 – Complexidade do Problema… .................… … … … … … … .............. 27
3.3 – O Problema do Carteiro Chinês Não Direcionado (PCCND).................. 28
3.3.1 – Formulação para o PCCND… … … … … … … ...… … … … .................. 29
3.4 – O Problema do Carteiro Chinês Direcionado (PCCD)… ......… ............... 30
3.4.1 – Formulação para o PCCD… … … … … … … … … … … … .................... 31
3.5 – O Problema do Carteiro Chinês Misto (PCCM)… … … … … … ................. 32
3.5.1 – Formulação para o PCCM… ..… … … … … … … … … … … ................. 35
3.6 – O Problema de Roteamento em Arcos para m Veículos… … … .............. 38
3.6.1 – Formulação para o PRAC… … ...… … … … … … … … … … … … .......... 39
3.6.2 – Algoritmos Heurísticos para o PCCC… … … … … … … … ................. 41
3.6.2.1 – Algoritmo Seletor de Caminho (Path – Scanning)… ..… … .... 41
3.6.2.2 – Algoritmo de Construção e Remoção (Construct and Strike). 42
3.6.2.3 – Algoritmo de Aumento e Junção (Augment – Merge)… … ..... 43
vii
Capítulo 6 - Conclusão......................................................................................... 76
6.1 – Conclusões.............................................................................................. 76
6.2 – Sugestões para Trabalhos Futuros......................................................... 77
REFERÊNCIAS BIBLIOGRÁFICAS........................................................................ 79
APÊNDICE A............................................................................................................ 85
APÊNDICE B........................................................................................................................ 91
APÊNDICE C........................................................................................................................ 96
viii
LISTA DE TABELAS
ix
LISTA DE FIGURAS
Figura 3.1 – As sete pontes de Königsberg sobre o rio Pregel. Fonte: www.mat.uc.pt/
/~alma/escolas/pontes.....................................................................................................25
Figura 3.2 – Grafo que não é simétrico, porém euleriano. Fonte: Eiselt et al. (1995)
.........................................................................................................................................27
Figura 4.6 – Grafos resultantes ao final de cada iteração com os graus assumidos pelos
vértices durante a fase de construção.............................................................................59
x
Figura 4.8 – Grafo solução GS , simétrico e euleriano....................................................61
Figura 5.2 –Vetor utilizado para armazenar os pesos w(i,j) das arestas........................64
Figura 1A – G1: grafo não orientado; G2: digrafo; G3: grafo misto................................85
Figura 3A – Digrafo original com ofertas/demandas nos nós e seu grafo solução após
resolver o PFCM..............................................................................................................90
xi
Resumo da dissertação apresentada ao CCT/UENF como parte integrante dos
requisitos necessários para a obtenção do grau de Mestre em Ciências (M.Sc.) em
Engenharia (área de Engenharia de Produção).
06 de Julho de 2004
xii
Submitted to the CCT/UENF in partial fulfillment of the requirements for the degree of
Master of sciences.
July – 2004
The growth of the world population and the globalization of the consumption,
have as consequence the swelling of the cities and the generation of great amounts of
garbage, generating problems of environmental order, city planning, social and
economical. The main reason of this work was to contribute with a proposal for the
administration of the collection and transport of the domestic garbage, tends as
objective minimizes the financial costs. This dissertation turns on the modeling of the
collection of the domestic garbage, made by a compactor truck, formulated through
models of Integer Linear Programming (ILP) and of the resolution of one of the
presented models, through an algorithm based on GRASP metaheuristic, proposed for
the optimization of the route executed by the vehicle collector in your respective
collection sectors. For so much, the model uses a mixed graph G = (V, A ∪ E) to
represent the collection sectors, facilitating, like this, the implementation computational
of the calculation of a more economical route.
In the literature, the approached problem is denominated as Mixed Chinese
Postman Problem (MCPP) that is a special class of the acquaintance Arcs Routing
Problems (ARP), whose resolution through exact algorithms has NP-Complete
complexity. They are also presented, some comparisons among the values (costs) of
the resultants solutions of the proposed algorithm (implemented in the way it Consoles
Application of DELPHI 5®) and your respective great solutions, obtained of the model of
resolved ILP through the software LINDO 6.1. The algorithms were compared, using
generated graph (instances) starting from the road network of the city of Campos of
Goytacazes.
xiii
1
Capítulo 1
Introdução
Capítulo 2
60% 47,1%
40% 30,5%
22,3%
20% 10% 13%
0%
Lixoes Aterros Sanit. Aterros Cont.
1989 2000
Ainda segundo dados do IBGE, dos 5.507 municípios brasileiros, 4.026 (73,1%)
têm população até 20.000 habitantes. Nestes municípios 68,5% dos resíduos gerados
são vazados em lixões e em alagados. Se tomarmos como referência a quantidade de
lixo gerada por eles, em relação ao total da produção brasileira, a situação é menos
grave, pois em conjunto coletam somente 12,8 % do total brasileiro (20.658 t/dia). Isto é
menos do que o gerado pelas 13 maiores cidades brasileiras, com população acima de
1 milhão de habitantes. Elas coletam 31,9 % (54.916 t/dia) de todo o lixo urbano
brasileiro, e têm seus locais de disposição final em melhor situação: apenas 1,8 % (929
t/dia) é destinado a lixões, o restante está sendo depositado em aterros controlados ou
sanitários.
Com relação à disposição e tratamento dos resíduos sólidos de serviços de
saúde (lixo hospitalar, responsável por vários casos de doença), em 2000 houve
melhora, com 539 municípios encaminhando-os para aterros de resíduos especiais
(69,9 % próprios e 30,1 % de terceiros), enquanto em 1989, apenas 19 municípios
davam este destino aos resíduos hospitalares. Em número de municípios, 2.569
depositam este tipo de lixo, nos mesmos aterros que os resíduos comuns, enquanto
539 já estão enviando-os para locais de tratamento ou aterros de segurança.
Em síntese, o brasileiro convive com a maioria do lixo que produz. Montanhas
cada vez maiores de resíduos sólidos representam uma séria ameaça à saúde e a
8
2
Instituto de Pesquisas Tecnológicas, São Paulo;
9
*HUDomR
$FRQGLFLRQDPHQWR
&ROHWD
(VWDomRGH 3URFHVVDPHQWRH
7UDQVIHUrQFLDRX 5HFXSHUDomR
7UDQVERUGR
'LVSRVLomR)LQDO
2.2.2 – Acondicionamento
2.2.3 - Coleta
3
Fonte: Jornal O ESTADO DE S. PAULO, São Paulo, 07/12/2002.
12
1 L Dg Dd Q
Ns = . + 2 . + 2 . . (1)
J V
c V
t t C
V
Onde:
Quanto aos tipos de disposição final dos resíduos, podem ser classificados em
quatros tipos básicos (IBGE, 2000):
• Aterro sanitário - técnica de disposição do lixo, fundamentado em critérios
de engenharia e normas operacionais específicas, que permite a confinação
segura em termos de controle da poluição ambiental e proteção à saúde
pública;
• Aterro controlado - local utilizado para despejo do lixo coletado, em bruto,
com cuidado de, após a jornada de trabalho, cobri-lo com uma camada de
terra, sem causar danos ou riscos à saúde pública e a segurança,
minimizando os impactos ambientais;
• Lixão ou Vazadouro a céu aberto - disposição final do lixo pelo seu
lançamento, em bruto, sobre o terreno sem qualquer cuidado ou técnica
especial;
• Vazadouro em áreas alagadas - disposição final do lixo pelo seu
lançamento, em bruto.
4
Fonte:Jornal Folha da Manhã, Campos dos Goytacazes, 24/09/94;
21
5
Fonte:Jornal Monitor Campista, Campos dos Goytacazes, 18/06/97.
22
Capítulo 3
seus vértices tem grau par, é dito simétrico se d i− = d i+ para cada vértice i∈V e é dito
ser balanceado se, para qualquer subconjunto S de vértices, a diferença entre o
número de arcos direcionados de S para V \ S e o número de arcos direcionados de V \
S para S não é maior que o número de arestas (não direcionadas) unindo S e V \ S
(EISELT et al., 1995a) (CORBERÁN et al., 2002).
Uma definição que deve ser ressaltada é a de grafo euleriano. Um grafo G
conectado é euleriano, se existe um caminho fechado em G contendo cada arco
exatamente uma vez e cada vértice ao menos uma vez.
Ford e Fulkerson (apud EISELT et al., 1995a) estabeleceram as condições
necessárias e suficientes para que um grafo conectado seja euleriano:
1. Seja G não direcionado, G é euleriano se e somente se todo vértice do grafo
tem grau par, isto é, um número par de arestas incidentes;
2. Seja G direcionado, G é euleriano se e somente se o número de arcos que
entram e saem de cada vértice são iguais. Em outras palavras, o grafo deve
ser simétrico;
3. Seja G misto, G é euleriano se e somente se todo vértice tem grau par e,
além disso, é balanceado.
1 2
Dado um grafo misto fortemente conectado G = (V, E ∪ A), sendo V = {v1, v2,
..., vn} o conjunto de vértices ou nós, E o conjunto de arestas, A = {(vi, vj): vi,
vj∈ V e i≠j} o conjunto de arcos e um custo não-negativo ce (que pode ser a
distância ou tamanho do arco/aresta) para cada e∈E ∪ A, o PCCM consiste
em encontrar uma rota de custo mínimo passando através de cada ligação
e∈E ∪ A ao menos uma vez.
ser considerado como a solução para o PCC. Por outro lado, se um grafo
(direcionado, não direcionado ou misto) não é euleriano, o PCC pode ser
formulado como um problema, cujo objetivo é encontrar um conjunto de cópias de
ligações com o menor custo, tal que, quando adicionadas a G seja obtido um grafo
euleriano. Assim, o grafo aumentado formado por G mais as cópias das ligações
adicionadas, pode ser considerado como a solução do problema. Na figura 3.3, a
cópia de menor custo adicionada está representada pela aresta tracejada.
1 2 1 2
3 3
3 1 1 3 1 1
3 3
Grafo não euleriano Grafo aumentado euleriano
s.a.
∑∈
( vi , v j ) δ ( i )
xij ≡ 1(mod 2) se vi ∈ T (2)
∑∈δ
( vi , v j ) (i )
xij ≡ 0(mod 2) se vi ∈ V \ T (3)
Neste modelo, a relação (1) representa a função objetivo, que busca o número
de arestas de menor custo que irão aumentar o grafo G. A relação (2) representa as
restrições que garantem que o número de arestas adicionadas incidentes nos vértices
de grau ímpar seja ímpar, enquanto a relação (3) representa restrições que garantem
que o número de arestas adicionadas incidentes nos vértices de grau par seja par. A
relação (4) explicita que os possíveis valores assumidos pelas variáveis xij são 0 ou 1.
Este modelo pode ser resolvido como um problema de emparelhamento no
grafo K|T| = (T,ET), onde T é o conjunto de vértice de grau ímpar, ET = {(vi , vj): vi , vj∈T,
i<j}, e o custo de (vi , vj) ∈ ET é o menor custo, dentre todos os caminhos existentes
entre os vértices vi e vj em G. O Grafo G’ é então obtido de G pela introdução das
30
PASSO 3 - Sejam e1, e2 duas arestas incidentes em v na primeira rota, e sejam e3,
e4 duas arestas incidentes em v na segunda rota. Una as duas rotas em uma rota
simples: por exemplo, começando em v com a aresta e3, percorra a segunda rota
até retornar a v por e4 , então continue na primeira rota partindo de e2 até retornar a
v por e1. Se todas as arestas foram percorridas, pare. Caso contrário, vá para o
PASSO 2;
Além deste algoritmo, outros podem ser destacados como, por exemplo, o
algoritmo de Fleury, o algoritmo Next-Node e o algoritmo Maze-Search. Tais algoritmos
possuem formas diferentes de concepção do circuito euleriano (EDMONDS e
JOHNSON, 1973).
EISELT et al., 1995a). Deve-se notar que, ao contrário do caso não direcionado, este
problema pode não ter a mesma solução se G for somente conectado. Para garantir a
existência de uma solução, o grafo deve ser fortemente conectado, isto é, deve existir
um caminho direcionado entre todos os pares de vértices. Edmonds e Johnson (1973),
Orloff (1974) e Bodin e Beltrami (1974) mostraram como um grafo euleriano de custo
mínimo pode ser construído, resolvendo um problema de transporte.
Para a formulação como um problema de fluxo de custo mínimo, são feitas as
seguintes considerações. Seja I o conjunto de vértices vi , tal que a diferença entre o
número de arcos que entram em vi e o número de arcos que saem, seja igual a si , e J o
conjunto de vértices vj , tal que a diferença entre o número de arcos que saem de vj e o
número de arcos que entram seja igual a dj. Desta forma, si pode ser interpretado como
uma oferta no vértice i, e dj como uma demanda no vértice j e, além disso, cij denotará o
tamanho do menor caminho de vi para vj.
M in ∑ ∑ c ij x ij (5 )
vi ∈ I v j ∈ J
s .a .
∑
v j∈J
x ij = s i (vi ∈ I ) (6 )
∑
vi ∈ I
x ij = d j (v j ∈ J ) (7 )
x ij ≥ 0 , in teiro ( v i ∈ I , v j ∈ J ) (8 )
Nesta formulação, a variável xij representa o número de vezes extra que cada
arco (i, j) será atravessado. Desta forma, a função objetivo na relação (5), busca
aumentar só àqueles arcos de menor custo. Em (6), as restrições garantem que os
32
arcos aumentados, partindo dos vértices vi, atendam suas ofertas, enquanto em (7) as
restrições garantem que os arcos aumentados, entrando nos vértices vj , atendam suas
demandas. Na relação (8), as restrições garantem a integralidade das variáveis. Uma
vez que um grafo euleriano é determinado, um circuito euleriano pode ser traçado
através do procedimento sugerido por van Aardenne–Ehrenfest e de Bruijn (1951),
também descrito em Edmonds e Johnson (1973).
Existem outros algoritmos que podem determinar o circuito euleriano em grafos
direcionados. Em particular, será apresentado um algoritmo que foi utilizado na
implementação do programa OTIMIZA_COLETA proposto nesta dissertação. No
Apêndice B, é ilustrado um exemplo de como trabalha o algoritmo 3.2 objetivando sanar
eventuais dúvidas:
PASSO 2 – Identifique um vértice w ∈ V adjacente a v0, tal que (v0 , w) ∈ A seja não
usado. Rotule (v0 , w) como usado e vá ao PASSO 3. Se w não foi encontrado e
todas os arcos já foram usados, PARE. Caso contrário, vá ao PASSO 4;
PASSO 2 – Seja v um vértice com pelo menos uma aresta (v, w) incidente. Faça
v1:= v e v2:= w.
PASSO 3 – Oriente (v1, v2) de v1 para v2. Se v2 = v , vá para o PASSO 1.
PASSO 4 – Faça v1:= v2 e identifique uma aresta (v1, v2) incidente em v1. Vá para o
PASSO 3.
34
Minimize ∑ ∨ ∧
cs x s (9)
s∈ A∪ E ∪ E
s.t.
ye’ + ye’ ≥ 1 ∀e ∈ E (10)
∨ ∧
xs = y s’ + y s ∀s ∈ A ∪ E ∪ E (11)
∑ xs − ∑ xs = 0 ∀ v ∈ V (12)
s∈δ + ( v ) s∈δ − ( v )
ya’ = 1 ∀a ∈ A (13)
∨ ∧
ye’ ∈ {0,1} ∀e ∈ E ∪ E (14)
∨ ∧
y s ≥ 0, inteiro ∀s ∈ A ∪ E ∪ E . (15)
arcos unindo quaisquer dois vértices distintos no grafo aumentado. Já foi visto no
∧ ∨
parágrafo anterior o significado de E e E . Portanto as variáveis ye’ e ye’ representam
aumentado.
As restrições (10) representam a necessidade de que haja ao menos uma cópia
de cada aresta no grafo aumentado. As restrições (12) garantem que o grau de cada
-
vértice do grafo aumentado seja zero, uma vez que δ (v) (é o conjunto de arcos e
+
arestas orientadas que entram em v) e δ (v) (é o conjunto de arcos e arestas orientadas
que saem de v) referem-se, respectivamente, ao grau de entrada e saída dos vértices
no grafo aumentado. Observe que esta notação de grau, embora seja diferente da
apresentada no início do capítulo, representa a mesma idéia.
Além dos autores já descritos, Nobert e Picard (1996) desenvolveram um
algoritmo de plano de corte baseado em PL para resolver o PCCM otimamente.
Contudo, todos estes métodos exatos são computacionalmente ineficientes, de modo
que apenas problemas de médio e pequeno porte podem ser resolvidos sem
dificuldades computacionais em tempo satisfatório (PEARN e CHOU, 1999).
Edmonds e Johnson (1973) já tinham sugerido uma heurística para resolver o
PCCM aproximadamente. A heurística consistia basicamente de duas fases. A Fase1
convertia o grafo original em um grafo par, por considerar cada arco como uma aresta,
e aplicava-se o algoritmo de Emparelhamento de Custo Mínimo. A Fase2 transforma o
grafo obtido da Fase1 em um grafo simétrico por meio do algoritmo de Fluxo de Custo
Mínimo. Porém, desde que o grafo simétrico transformado nem sempre se mantém par,
a rota do carteiro pode não ser construída. Frederickson (1979) modificou a heurística
adicionando uma nova fase, Fase3. A nova fase transforma novamente o grafo
resultante em par, podendo, assim, ser construída a rota do carteiro. Esta última
heurística foi chamado de MIXED 1 (PEARN e LIU, 1995) e gera boas soluções
satisfazendo as condições necessárias e suficientes para que um seja euleriano. A
seguir, serão descritas as fases do algoritmo MIXED 1:
37
PASSO 2.2 - Encontre o fluxo de custo mínimo sobre a rede G2. Faça Yij , Yji , Yij’ ,
Yji’ e Ykl ser o número de unidades de fluxo entre os arcos (i, j), (j, i), (i, j)’, (j, i)’ e (k,
l) respectivamente.
PASSO 2.3 - Construa uma rede simétrica G3 = (V, E3, A3). Inicialmente, faz-se E3 =
∅, e A3 = A1.
(a) se Yij’ + Yji’ = 1, ponha Yij’ copias do arco (i, j) e Yji’ copias do arco (j, i) em A3;
(b) se Yij’ + Yji’ ≠ 1, ponha uma copia da aresta (i, j) em E3;
(c) ponha Yij copias do arco (i, j) e Yji copias do arco (j, i) em A3;
(d) ponha Ykl copias do arco (k, l) em A3.
38
n n K
Minimize∑∑∑ cij xijp (16)
i =1 j =1 p =1
n n
s.a. ∑ xkip -∑ xikp = 0 para i=1,...,n
k =1 k =1
(17)
p=1,...,K,
K
qij
∑ ( l p
ij + l p
ji ) = para (i,j) ∈ E, (18)
p =1 W
∑∑l
i =1 j =1
p
q ≤W
ij ij para p=1,...,K, (20)
~
∑∑ xijp ≤ Q -1 + n 2 y p~
1q
~ ~
vi ∈Q v j ∈Q
(21)
∑∑x ~ ~
p
ij ≥ 1 - y p~
2q
~
n −1
para p = 1,..., K ; q = 1,..., 2 − 1
vi ∈Q v j ∉Q
y p~ + y p~ ≤ 1; E todo subconjunto não
1q 2q vazio Q~ de {2,3,…,n}
y ~ , y ~ ∈ {0,1}
p p
1q 2q
x , l ∈ {0,1}
p p (22)
ij ij
(W ≥máx qij ); cij a distância do vértice i ao vértice j (custo de (i, j)); a variável xijp = 1 ,
o veículo p serve a aresta (i,j) e 0 em caso contrário; z denota o menor inteiro maior
ou igual a z.
A relação (16) representa a função objetivo, que busca minimizar a distância
total viajada. As restrições (17) asseguram a continuidade da rota. As restrições (18)
declaram que cada aresta com demanda positiva é servida exatamente uma vez. As
restrições (19) garantem que a aresta (i,j) pode ser servida pelo veículo p somente se
41
ela é atravessada pelo mesmo. A capacidade do veículo não é violada por causa da
restrição (20). As restrições na relação (21) proíbem a formação de sub-rotas ilegais.
~ ~
Observe que cada índice q corresponde a um subconjunto do conjunto Q . Finalmente
as restrições em (22) garantem a integralidade das variáveis.
~
Observe que para um dado veículo p e um subconjunto de vértices Q , somente
p p
uma das duas variáveis binárias y ~ ou y ~ pode assumir valor 1. Desta forma,
1q 2q
~
qualquer ciclo com um conjunto de vértices em Q e arestas atravessadas pelo veículo p
~
deve estar conectado a V \ Q (bem como ao depósito, no vértice 1) formalmente
estabelecido pela relação:
~
∑∑x ~ ~
p
ij > Q -1 ⇒ y p~ =1 ⇒ y p~ =0 ⇒
1q 2q
∑∑x~ ~
p
ij ≥ 1.
vi ∈Q v j ∈Q vi ∈Q v j ∉Q
Diversos procedimentos heurísticos têm sido propostos para o PRAC, que por
sua vez, segundo Eiselt et al. (1995), podem ser classificados em 3 categorias: 1)
métodos construtivos simples; 2) métodos construtivos de duas fases; e 3) métodos de
melhoria.
junção de um arco que seja mais promissor, até que a capacidade do veículo seja
extrapolada. A partir daí, o menor caminho de retorno ao depósito é selecionado. Na
escolha do arco mais promissor, cinco critérios de otimização são considerados a
saber:
Dado um caminho do depósito para o vértice i, escolhe-se o arco (i, j), sujeito à
restrição de capacidade, tal que: (1) a distância cij , por unidade de demanda restante é
minimizada; (2) a distância cij, por unidade de demanda restante é maximizada; (3) a
distância de retorno do vértice j até o depósito é minimizada; (4) a distância de retorno
do vértice j até o depósito é maximizada; (5) se o veículo está com menos da metade
cheia, maximize a distância de retorno do vértice j até o depósito, caso contrário,
minimize esta distância. A idéia principal é que, um número menor de ciclos longos
pode ter uma distância total menor. Independente do critério utilizado, uma vez que a
capacidade do veículo é totalmente utilizada, o ciclo será fechado pelo menor caminho
de retorno ao depósito.
No artigo de PEARN (1991) se comenta que, o algoritmo Path–Scanning é um
tanto simples de implementar, necessitando de pouco mais que 200 linhas de código
FORTRAN, produz bons resultados e requer relativamente pouco tempo de
processamento. Sua complexidade é de O(n3).
eliminados, tal que o grafo passado para o Passo 3 do algoritmo contenha somente
vértices e demandas em arcos não servidos. Este procedimento, de construir e remover
ciclos, será repetido até que nenhum ciclo mais seja encontrado.
iii) No terceiro e último passo, o algoritmo toma o grafo do Passo (ii) e adiciona
um conjunto de arcos artificiais, de custo mínimo, para garantir que o depósito seja de
grau par e que todos os outros vértices do grafo corrente sejam de grau par. O
algoritmo realiza isso encontrando um emparelhamento de peso mínimo entre os
vértices de grau ímpar do grafo corrente. Os arcos artificiais com seus respectivos
custos são adicionados, como conseqüência do cálculo dos caminhos de custo mínimo
entre os vértices de grau ímpar. Quando o depósito é de grau zero, é substituído por
dois vértices artificiais, que são conectados por um arco com um alto custo proibitivo
para garantir que ele não seja usado no emparelhamento. O grafo corrente, incluindo os
arcos artificiais determinado pela solução do emparelhamento é então retornado ao
Passo I(i) do algoritmo. As iterações permanecem entre os passos (i) – (ii) até que não
existam mais arcos a serem servidos. Este algoritmo foi implementado por Golden et
al.(1983) em FORTRAN, utilizando uma sub-rotina de emparelhamento de custo
mínimo, desenvolvida por Deris e Kazakidis (1979). A complexidade deste algoritmo é
de O(mn3) (PEARN, 1991).
Este procedimento foi originalmente proposto por Golden e Wong (1981) para
resolver o PCCC e o PRAC. Posteriormente, algumas modificações no critério do
cálculo da economia foram propostas por Golden et al. (1983), no intuito de melhorar o
Passo 3 (a Junção) do algoritmo. Os passos do algoritmo são descritos abaixo:
PASSO 1–INÍCIO: todas as demandas nos arcos são servidas por ciclos separados;
No Passo 1, constrói-se ciclos iniciais tal que cada ciclo sirva exatamente a um
aresta. Isso é feito encontrando o caminho mínimo entre os vértices extremos de cada
aresta e o depósito. No Passo 2, ordena-se os ciclos encontrados do maior para o
menor com respeito ao custo (distância). O maior ciclo recebe o número 1, e assim
sucessivamente. A seguir, tenta-se servir a demanda de um arco localizado em um ciclo
menor por meio de um ciclo maior.
Por exemplo, na primeira rodada se têm m ciclos e, se analisa se a demanda do
arco no ciclo i+1 pode ser servida no ciclo i, isso é feito e o ciclo i+1 é desconsiderado.
Da mesma forma, se a demanda do arco no ciclo i+2 pode ser servida no ciclo i, isso é
feito e o ciclo i+2 é descartado, e assim sucessivamente. Se o ciclo i atinge sua
capacidade, ele é separado e o aumento começa no próximo ciclo. O processo continua
até que todos os ciclos tenham sido considerados.
O Passo 2 resulta na formação de um número de ciclos que cai em uma das
três classes: (1) ciclos com a capacidade atendida e separados; (2) ciclos
desconsiderados, pois as demandas de seus arcos puderam ser servidas por ciclos
maiores; (3) ciclos com demanda em um ou mais arcos, porém com capacidade não
preenchida.
No Passo 3 procura-se unir pares de ciclos através dos vértices comuns de
ambos os ciclos, que estão enquadrados na terceira categoria acima. O ciclo unido ou
fundido deve obedecer à limitação de capacidade do veículo e deve servir ao mesmo
conjunto de arcos dos dois ciclos originais.
A seguir, é apresentado um exemplo extraído de Golden et al. (1983) para
ilustrar o procedimento descrito acima. Considere o exemplo da Figura 3.5 abaixo onde
os custos de cada aresta estão indicados, o depósito está no vértice 1, as arestas
possuem demandas unitárias e a capacidade do veículo é de 4 unidades.
45
Dep.
5
3
4 7
5 5
3 6
Número Custo
do do Ciclo
ciclo ciclo
1 16 1 4 6 1
2 15 1 5 6 1
3 14 1 4 1
4 13 1 3 6 1
5 10 1 5 1
6 10 1 2 6 1
7 8 1 6 1
8 8 1 3 1
9 6 1 2 1
Número Custo
do do Ciclo
ciclo ciclo
1 16 1 4 6 1
2 11 1 5 6 1
4 9 1 3 6 1
6 6 1 2 6 1
5
3
4 7
5 5
3 6
Nome
da Economias Ciclo
Junção
T24 8 1 5 6 3 1
T26 8 1 5 6 2 1
T46 8 1 3 6 2 1
5
3
4 7
5 5
3 6
1 4 6 1
1 5 6 3 1
1 2 6 1
Capítulo 4
4.1 – Introdução
Caixeiro Viajante (PCV), que consiste em um vendedor sair de uma cidade chamada
origem, visitar cada uma das n-1 cidades restantes uma única vez, e retornar à cidade
origem percorrendo a menor distância possível. Na literatura, a rota fechada que passa
uma única vez pelos vértices de um grafo é conhecida como ciclo hamiltoniano. O PCV
busca um ciclo hamiltoniano de custo mínimo. Desta forma, a dificuldade de solução do
PCV reside no grande número de soluções viáveis (ciclos hamiltonianos) existentes,
gerando aproximadamente (n-1)!/2 rotas possíveis. Portanto, mesmo com os melhores
computadores, seria impraticável enumerar todas as rotas possíveis, para valores
elevados de n, e logo identificar o ciclo de menor custo.
Esta dificuldade motivou o surgimento de algoritmos heurísticos destinados a
encontrar “boas” soluções ao invés do ótimo. Segundo Souza (2002), as heurísticas
podem ser definidas como uma técnica que procura soluções próximas da ótima a um
custo computacional razoável, sem, no entanto, estar capacitada a garantir a
otimalidade, bem como garantir quão próximo, uma determinada solução aproximada,
está da solução ótima.
A partir da junção de conceitos das áreas de Otimização e Inteligência Artificial,
foi possível construir melhores estratégias, conhecidas como “metaheurísticas”. As
metaheurísticas são procedimentos de busca local, destinados a encontrar uma boa
solução, eventualmente a ótima, consistindo na aplicação, em cada passo, de uma
heurística subordinada, a qual tem que ser modelada para cada problema específico.
Contrariamente às heurísticas convencionais, as metaheurísticas são de caráter geral e
tem condições de escapar de ótimos locais. De acordo com Souza (2002), as
metaheurísticas diferenciam-se entre si pelas seguintes características:
a) critério de escolha de uma solução inicial;
b) definição da vizinhança N(s);
c) critério de seleção de uma solução vizinha dentro de N(s);
d) critério de término.
Pode-se destacar como metaheurísticas os seguintes procedimentos:
Algoritmos Genéticos (AG), Redes Neurais, Simulated Annealing (Têmpera Simulada),
Busca Tabu (BT), GRASP (Greedy Randomized Adaptive Search Procedure), VNS
(Variable Neighborhood Search), Colônia de Formigas, entre outros. A seguir será
51
Procedimento Construção(g(.),α,s);
1 s←∅;
2 Inicialize o conjunto C de candidatos;
3 enquanto (C ≠ ∅) faça;
4 gmin ← min {g(e) | e ∈ C};
5 gmax ← máx {g(e) | e ∈ C};
6 LCR={e ∈ C | g(e) ≤ gmin + α (gmax – gmin)};
7 Selecione um elemento e∈ LCR aleatoriamente;
8 s←s ∪ { e };
9 Atualize o conjunto C de candidatos;
10 fim-enquanto;
11 Retorne s;
Fim Construção;
d(i)=3
d(j)= -4
Portanto, após todos os pesos w(i,j) terem sido calculados, o conjunto U será
organizado em ordem decrescente de pesos w. A cada passo na fase de construção,
uma aresta (i, j) é aleatoriamente selecionada entre os λ primeiros elementos de U,
onde λ é o tamanho da LCR. Então a aresta (i,j) é orientada do vértice com maior grau
para o vértice com menor grau. Se i e j tiverem o mesmo grau, então (i,j) é
aleatoriamente orientado. Os conjuntos U e Ed são atualizados através da retirada da
aresta (i,j) de U e a inserção desta no conjunto Ed. Do mesmo modo d(i), d(j) e w(i,j) são
também atualizados. A fase de construção termina quando todas as arestas tiverem
sido selecionadas e orientadas. Conseqüentemente, quanto maior o número de arestas
do grafo, mais tempo levará para a fase de construção ser finalizada. Desta forma, a
fase de construção termina após |E| passos. Logo, se executa o cálculo de Fluxo de
custo mínimo o PFCM sobre o grafo direcionado GF =(V, A ∪ Ed ∪ Ed’), com demandas
e ofertas computadas com respeito aos arcos em A ∪ Ed, onde Ed’ é o conjunto de
arcos paralelos àqueles em Ed com o mesmo custo, porém com direções opostas.
Adicionando os arcos pertencentes à solução do PFCM ao grafo G=(V, A ∪ Ed), obtém-
se um digrafo GS =(V, A ∪ Ed ∪ AF), simétrico e euleriano, onde AF é formado pelos
arcos utilizados na solução do PFCM. Associado a este grafo estará uma rota T com
custo Z(T) correspondente a uma solução do grafo misto original. Após estes passos,
segue-se a fase de melhoria.
da rota T obtida na fase de construção sobre o grafo que é a solução do PCCM. O grafo
solução, chamado de GS, é representado por um digrafo (grafo orientado) fortemente
conectado, contendo todos os arcos originais e arestas orientadas do grafo e uma ou
mais cópias destas ligações. Deve-se notar, que no grafo solução existirá ou um arco
simples, dois arcos com direções opostas ou dois ou mais arcos, todos eles com a
mesma direção, associado a cada aresta original e ∈ E.
Dados dois vértices i e j unindo um caminho de cópias, pode-se efetuar a
melhoria, através da substituição destas cópias pelas cópias dos arcos do caminho
mínimo em G unindo tais vértices. Portanto a melhoria, definida como m(i,j), é a
diferença entre o valor da função objetivo antes e após a substituição. Mais ainda, ela
pode ser calculada como o custo do caminho eliminado, menos o custo do caminho
mínimo adicionado. Em cada passo da fase de melhoria, se seleciona um par de
vértices que estejam unidos por um caminho de cópias. Para tanto, se deve explicitar
tais pares construindo um novo grafo misto G’=(V, E’, A’), derivado do grafo solução Gs,
como segue:
Para cada arco original (i,j) ∈ A coloque n - 1 cópias dele em A’, onde n é o
número de vezes que ele aparece em Gs. Para cada aresta e∈ E, tendo exatamente
dois arcos com direções opostas associados em Gs,, coloque uma aresta em E’, caso
contrário, n –1 cópias de seus arcos associados são adicionados a A’.
Então, computa-se estas componentes conectadas do grafo G’ e se reduz a
busca a pares de vértices dentro de cada componente. No intuito de reduzir o esforço
computacional, esta busca estará restrita apenas a vértices adjacentes a somente um
outro vértice. Se o valor da melhoria for positivo a troca é realizada, caso contrário, será
rejeitada. A fase de melhoria termina quando todos os pares de vértices forem
revisados e nenhuma melhoria possa ser mais realizada.
Após completar um número de iterações igual a NITER (Nmáx), o algoritmo é
finalizado e a melhor solução encontrada é retornada como solução final. O
pseudocódigo do algoritmo GRASP é apresentado a seguir:
57
1 iterm 0;
2 Niter← Nmáx;
3 enquanto (iter < Niter ) faça
4 iter ← iter +1;
seja Ed = ∅ e U = E. Compute o peso(e) = w(i,j); para todo e = (i,j) ∈ U;
Fase de Construção:
w(i, j) de cada aresta são calculados segundo os casos já descritos na seção 4.3.1. A
tabela 4.1 a seguir se refere à orientação das arestas do grafo, o qual foi executado
pelo laço enquanto do passo 5 no algoritmo.
ITER PESOS U Ed
w(4,5)=3; w(1,6)=ε;
0 {(1,6), (3,6),(4,5),(5,7)} ∅
w(3,6) = ε;w(5,7) = ε
w(4,5)=3; w(1,6)=ε;
1 {(1,6),(3,6),(4,5)} {(5,7)}
w(3,6) = ε;w(5,7) = H
w(1,6) = H;w(3,6) = ε;
2 {(3,6),(4,5)} {(5,7), (6,1)}
w(4,5) = ε
4 w(3,6)=-H. ∅ {(5,7),(6,1),(5,4),(6,3)}
A seguir, a seqüência de grafos apresentada pela fig. 4.6 mostra a aresta que
foi direcionada após cada iteração e os respectivos graus recalculados, assim pode ser
efetuado o cálculo dos novos pesos.
G = (V, AE)
0 0
2
2 1
3
3 6
1 1 2
0 3 6 7 0
2 1 2
5
4 5
3
-2 1
(a)misto inicial.
(a) - Grafo
60
0 0 0 1
2 2
2 1 2 1
3 3
3 6 3 6
1 1 0 2
1 2 3 6 7 1
0 3 6 7 1 0
2 1 2 2 1 2
5 5
4 5 4 5
3 3
-2 0 -2 0
(b) - G após a 1º iteração interna. (c) - G após a 2º iteração interna.
0 1 0 1
2 2
2 1 2 1
3 3
3 6 3 6
1 0 2 1 -1 2
0 3 6 7 1 1 3 6 7 1
2 1 2 2 1 2
5 5
4 5 4 5
3 3
-1 -1 -1 -1
(d) - G após a 3º iteração interna. (e) - G após a 4º iteração interna.
Figura 4.6 – Grafos resultantes ao final de cada iteração do passo 5 do algoritmo, com
os respectivos graus finais dos vértices durante a fase de construção.
GF = (V, AEdEd´)
0 1
2
2 1
3
3 6
1 2
1 3 6 7 1
-1
2 1 2
5
4 5
3
-1 -1
Figura 4.7 – Grafo GF onde será aplicado o PFCM.
61
Note que os arcos tracejados pertencem ao conjunto Ed´ , isto é, são arcos que
são acrescentados em sentido contrário as arestas que foram direcionadas. Os arcos
utilizados na solução do PFCM em GF, identificados como AF (arcos em linha cheia),
serão acrescentados ao grafo G=(V, A ∪Ed ) , obtendo assim o grafo GS da figura 4.8:
GS = (V, AEdAF)
2
2 1 3
3
3 6
1 2
3 1 6 2 7
2
2 1 2 22
5
4 3 5
3
Figura 4.8 – Grafo solução GS , simétrico e euleriano.
Fase de Melhoria:
G´ = (V, A´ , E´)
2 1
3
1 2
3 6 2 7
22
4 5
3
Capítulo 5
Implementação Computacional e Testes
problemas clássicos da teoria dos Grafos como: Caminho Mínimo, Fluxo Custo Mínimo
e Circuito de Euler.
O programa completo do algoritmo recebeu o nome de OTIMIZA_COLETA, e
foi implementado utilizando o modo Console Aplication do DELPHI 5®.
Adicionalmente, foram preparadas outras pequenas rotinas. Por exemplo, para
calcular os graus dos vértices no grafo utiliza-se o Procedure CalculaOfertaDemanda
armazenado-os em um vetor (array unidimensional) chamado OF_DM. A Function
Qaresta foi utilizada para computar o número de arestas (arcos não direcionados) do
grafo. O peso de cada aresta é calculado por meio do Procedure ComputaPesos e
armazenado em um vetor chamado LCR, com cada índice composto pelos seguintes
campos: Peso, Noinicial, Nofinal, Ind_i, Ind_ j (Figura 5.2). As três rotinas mencionadas
acima, são utilizadas nos passos 4 e 8 do procedimento da figura 4.5, descrito no
Capítulo 4. Em particular, a rotina CalculaOfertaDemanda é chamada novamente no
passo 10 do procedimento.
Vetor Lista
Custo
..........
PRT
Nof
Noi
Nofinal
Ind_ I
Ind_ j
..........
Peso
Figura 5.2 - Vetor utilizado para armazenar os pesos w(i,j) das arestas.
65
Através de uma adaptação feita no modelo da seção 3.5.1, foi possível obter a
solução ótima nos grafos testados. Tal adaptação é um novo modelo de PLI para o
PCCM, onde são consideradas algumas modificações. Sabendo-se que uma cópia
orientada de cada aresta e de cada arco será incluída no grafo aumentado ótimo, pode-
se considerar os custos destas cópias como constantes na função objetivo. Fazendo
isso, quando o problema for resolvido só será considerado o custo de aumento do
grafo, gerando uma redução no número de variáveis, pois serão suprimidas as variáveis
seção 3.5.1 passam a ser ye + ye = 1 , forçando cada aresta ser orientada em uma
’ ’
dada direção. O novo modelo, que é uma formulação de PLI com algumas variáveis
restritas a valores 0-1, fica então da seguinte forma:
Minimize ∑ ∨ ∧
cs ys + ∑
s∈A∪ E
cs (1)
s∈A∪ E ∪ E
s.t.
ye’ + ye’ = 1
∀e ∈ E , (2)
∨ ∧
xe = ye’ + ye ∀e ∈ E ∪ E , (3)
xa = ya ∀a ∈ A, (4)
∑ xs − ∑ xs = d (v) ∀v ∈V , (5)
s∈δ + ( v ) s∈δ − ( v )
∨ ∧
y ∈{0,1}
’
e ∀e ∈ E ∪ E , (6)
∨ ∧
ys ≥ 0, inteiro ∀s ∈ A ∪ E ∪ E . (7)
Com esta formulação, as restrições (3) e (4) podem ser eliminadas do modelo
sem nenhum prejuízo para a solução final, uma vez que estas só são usadas para
indicar o número de ligações que unem cada par de vértices. As restrições (5) garantem
que as ligações acrescentadas ao grafo atendam as ofertas ou demandas nos vértices,
68
isto é, seus graus sejam anulados tornando-o assim em um grafo simétrico. Lembrar
que d(v) representa o grau do vértice v, conforme visto na seção 4.3.1 do Capítulo 4.
Com esta formulação, em uma das instâncias, o novo modelo forneceu a
solução ótima em 1 minuto e 54 segundos para o caso do grafo com 50% das ligações
formadas por arcos e no caso do grafo com 30%, o ótimo foi obtido em 4 minutos e 3
segundos. No caso do grafo de 70%, a solução ótima foi obtida com um tempo menor
que 1 segundo. De posse dos valores ótimos de cada grafo, foi possível efetuar uma
comparação com os valores encontrados pelo programa OTIMIZA_COLETA. A tabela
5.1 apresenta diversos valores encontrados pelo programa OTIMIZA_COLETA para
diferentes tamanhos de λ na instância com 44 vértices. Optou-se tomar valores para λ,
tais que caracterizassem um algoritmo totalmente guloso (λ = 1) e totalmente aleatório
(λ = nº de arestas do grafo testado), e alguns valores intermediários a estas duas
situações. Para efetuar estes testes fixou-se o número de iterações GRASP em 1000,
isto é, Nmáx=1000.
Nos testes realizados, para efetuar a comparação com o ótimo, foram utilizadas
três instâncias (grafos) distintas, nomeadas da seguinte forma: grafo 44_118; grafo
44_108, grafo 44_91. Desta forma, o primeiro número indica o número de vértices dos
grafos, que neste caso é 44, enquanto o segundo número indica o número de ligações.
Deve-se ressaltar que, para esta contagem cada aresta é considerada como duas
ligações com direções contrárias (dois arcos). O que varia de um grafo para outro,
conforme visto anteriormente, é o número de arcos. A idéia de tomar grafos com 30%,
50% e 70% do total de ligações sendo arcos, tem por objetivo observar o
comportamento do algoritmo com relação ao esforço computacional e a qualidade das
soluções em setores mais residenciais, isto é, com poucas ruas de mão–única (30%) e
em setores mais centrais com poucas ruas de mão–dupla (70%).
O tamanho dos grafos utilizados (número de vértices e ligações) nos testes
comparativos baseou-se em uma estimativa da quantidade de lixo gerado e da
respectiva capacidade dos caminhões coletores. A partir daí, estimou-se o tamanho do
setor. Para tanto, foi considerada a média do número de pessoas por residência (Pres)
igual a 4, o número de residências por rua (Rrua) igual a 16, o número de habitantes por
rua (Hrua) igual a Hrua= Rrua x Pres e a quantidade do lixo gerado (k) igual a 800
g/hab/dia. Além disso, foi considerada uma capacidade de 15 m3 por caminhão,
equivalente a 3,5 t. considerando o peso específico médio do lixo solto de 250 kg/m
(CARVALHO, 2001). Daí tem-se a seguinte estimativa do tamanho do setor de coleta:
70
Rrua = 16;
Pres = 4;
Hrua = 16 x 4 = 64 ;
Considerando N o número máximo de ruas de um dado setor e Q a capacidade
do caminhão dado em gramas, temos que:
Q 3.500.000
N= = ≅ 68 ruas. (8)
H rua × k 64 × 800
Observe, que nas tabelas apresentadas existem colunas que não possuem
valores para certas instâncias. Isto significa que tal instância não foi testada para o
valor de λ em questão, pelo fato do total de arestas desta instância ser inferior ao
respectivo valor de λ. Devido à dimensão das instâncias testadas, foi tomado Nmáx =
500 para o número máximo de iterações do algoritmo GRASP, de forma a reduzir o
tempo de processamento.
73
Capítulo 6
Conclusão
6.1 – Conclusões
modelo exato por sua vez, aplicado à mesma instância encontrou o referido ótimo em 4
minutos e 3 segundos. Portanto, com o método proposto chega-se a uma solução
aproximada com apenas 5% do tempo gasto pelo método exato. No caso das
instâncias maiores, 150 e 200 vértices, por exemplo, só foram realizados testes
computacionais utilizando o método proposto.
A problemática da coleta de resíduos sólidos, por outro lado, deve ser encarada
de maneira multidisciplinar pelas conotações sócio-econômicas-culturais e de políticas
sustentáveis necessárias. Portanto, as propostas técnicas de meios que levem a uma
redução nos custos operacionais devem ser consideradas. Além disso, deverá estar
preparada para acompanhar o dinamismo das cidades pois, ao mesmo tempo em que
as cidades crescem, em população e extensão, passam constantemente por
modificações e suas redes viárias. Para atender a esta dinâmica, os setores
responsáveis por estes serviços necessitam de respostas rápidas e confiáveis. Ao final,
o que se espera é um serviço de maior qualidade para a população e que ao mesmo
tempo onere menos o orçamento do município.
Esta dissertação iniciou-se com a procura por informação sobre técnicas da
pesquisa operacional aplicada a problemática de gestão e coleta de lixo; desenvolveu-
se o estudo e a implementação de um algoritmo, proposto na literatura, para resolver o
Problema do Carteiro Chinês Misto (PCCM) utilizando a metaheurística GRASP
(Greedy Randomized Adaptive Search Procedure). Para realizar a implementação,
utilizou-se o método Simplex para Redes Eficiente (Goldfarb, 1990), no procedimento
que torna o grafo problema em um grafo simétrico e euleriano. Este tratamento
computacional do modelo foi desenvolvido no intuito de apresentar um método que
atenda em tempo razoável as exigências da coleta do lixo doméstico pelas ruas de uma
cidade.
Uma interessante verificação, que não deu tempo para se realizar, é um estudo
de caso na cidade de Campos, junto à empresa responsável pelos serviços de coleta,
de forma a colocar em prática o a proposta e avaliar os custos resultantes oriundos de
tal aplicação.
78
Fica ainda aberta a implementação dos algoritmos propostos para trabalhar com
o caso do roteamento de m veículos, com isto avaliara os setores de coleta dos
caminhões de uma empresa de coleta.
Sugere-se, também, utilizar outras metaheurísticas na implementação do
algoritmo do PCCM, para verificar a qualidade das soluções. Por exemplo, a
metaheurística Busca Tabu é uma sugestão, uma vez que esta permite escapar de
ótimos locais.
Por último se sugere, investir na criação de uma interface para o programa
implementado, de forma que se torne mais fácil de manipular e de maior potencial
comercial.
79
REFERÊNCIAS BIBLIOGRÁFICAS
BODIN, L., BELTRAMI, E.J. (1974) Networks and vehicle routing for municipal waste
collection, Networks, 4: 65-94.
BROWN, D.T. (1993) The legacy of the landfill: perspectives on the solid waste crisis.
St. Catharines: Brock University. Institute of Urban and Environmental Studies.
Disponível em <http://www.brocku.ca/epi/legacy.txt>. Acesso em: 8 ago. 2000.
BROWN, L. (2002) Nova York: a Capital Mundial do Lixo. Nota Jornalística acessada
em junho de 2003 www.wwiuma.org.br
CLARK, R.M., GILLEAN, J.I (1977) Solid wast collection: a case study, Operacional
Research Quarterly, 28(4): 795-806.
CORBERÁN, A., MARTÍ, R., SANCHIS, J.M. (2002) A GRASP heuristic for the mixed
Chinese postman problem. European Journal of Operational Research, 142: 70 – 80.
CHRISTOFIDES, N., BENAVENT, E., CAMPOS, V., CORBERÁN, A., MOTA, E. (1984)
An Optimal Method for the Mixed Postman Problem. In System Modelling and
Optimization, Lecture Notes in Control and Information Sciences (59), P. Thoft –
Christensen (ed.). Springer, Berlin.
EDMONDS, J., JOHNSON, E.L.(1973) Matching, Euler tours and the Chinese postman.
Mathematical Programming, 5: 88 – 124.
EISELT, H.A., GENDREAU, M., LAPORTE, G. (1995a) Arc routing problems, part I: the
Chinese postman problem. Operations Research, 43(2): 231 – 242.
EISELT, H.A., GENDREAU, M., LAPORTE, G. (1995b) Arc routing problems, part II: the
rural postman problem. Operations Research, 43(3): 399 – 414.
FEO, T.A, RESENDE, M.G.C., (1995) Greedy randomized adaptive search procedures.
Journal of Global Optimization, 6: 109 – 133.
FORD, L.R., FULKERSON, D.R. (1962) Flows in Networks, Pinceton University Press,
Princeton, N.J.
GOLDEN B.L., WONG R.T.(1981) Capacited arc routing problems. Networks, 11: 305-
315.
GOLDFARB, D., HAO, J., KAI, S.R. (1990) Efficient Shortest Path Simplex Algorithms.
Operations Research, 38(4): 624 – 628.
GRÖTSCHEL, M., WIN, Z. (1992) A Cutting Plane Algorithm for the Windy Postman
Problem. Mathematical Programming, 55: 339 – 358.
GUAN, M. (1962) Graphic Programming Using Odd and Even Points, Chinese
Mathematics, 1, 273 – 277.
HIERHOLZER, C. (1873) Uber die Möglichkeit, einen Linienzug ohne Wiederholung und
ohne Unterbrechung zu umfahren. Mathematische Annalen, VI: 30 – 32.
KAPPAUF, C.H., KOEHLER, G.J. (1979) The Mixed Postman Problem. Disc. Applied
Mathematics., 1: 89 – 103.
MARTINS, C. (2003) Prefeitura muda sistema de limpeza pública. Gente & Notícias,
Campos dos Goytacazes, 1 a 14 agosto, p.4.
MARINHO, C.E.V. (2001) Eficiência polinomial do método simplex para redes: análise
sobre um problema de caminho mais curto (PCMC), Dissertação (Mestrado em
Ciências de Engenharia), Campos dos Goytacazes – RJ, UENF, 88 p.
NOBERT, Y., PICARD, J.C. (1996) An optimal algorithm for the mixed Chinese Postman
Problem. Networks, 27: 95 – 108.
PEARN, W.L.(1991) Augment – Insert Algorithms for the Capacitated Arc Routing
Problem. Computers & Operations Research, 18(2): 189 – 198.
83
PEARN, W.L., LIU, C.M.(1995) Algorithms for the Chinese Postman Problem on Mixed
Networks. Computers & Operations Research, 22(5):479 – 489.
PEARN, W.L., CHOU, J.B. (1999) Improved Solutions for the Chinese Postman Problem
on Mixed Networks. Computers & Operations Research, 26:819 – 827.
RALPHS, T.K. (1993) On the Chinese postman problem. Operations Research Letters.
14: 123 – 127.
ROTH, B. W., ISAIA, E. M. B. I., ISAIA, T. (1999) Destinação final dos resíduos sólidos
urbanos. Ciência e Ambiente, 18: 25-40.
APÊNDICE A
Grafo Orientado
Grafo Misto
1 4 1 4 1 4
3 3 3
2 2 2
G1 G2 G3
Figura 1A – G1: grafo não orientado; G2: digrafo; G3: grafo misto.
86
Grau
O grau de um vértice é definido como o número de arcos e/ou arestas que lhe
são incidentes. Neste caso, o grau de entrada de um vértice vi é o número de arcos
convergentes (que entram em vi), enquanto o grau de saída é o número de arcos
divergentes (que saem de vi). No grafo G2 da figura 1A, o grau de entrada do vértice 4
é 2, e o grau de saída é 1. Da mesma forma, se cada aresta for considerada como dois
arcos orientados em sentidos opostos ,no grafo G3 o grau de entrada do vértice 4 é 2, e
o grau de saída é 1.
Adjacência de Vértices
Dado um grado G= (V, E) e uma aresta (vi, vj) ∈ E, diz-se que os vértices vi e vj
são adjacentes. Da mesma forma, para o arco (vi, vj) ∈ A tem-se vi e vj adjacentes.
Caminho
É uma seqüência de vértices v1, v2, ..., vk ∈ V, tal que (vi, vi+1) é uma aresta ou
um arco, com 1≤ i ≤ k-1. Um caminho de k vértices é formado por k-1 ligações,
definindo assim o comprimento do caminho. Se existe um caminho do vértice v1 até o
vértice vk , então vk é alcançável a partir de v1. Um caminho (v1, vk) é chamado aberto
se v1 ≠ vk e aberto se v1 = vk.
Circuito
É uma seqüência de vértices ligados por arcos com a mesma direção, com o
vértice final ligado ao vértice inicial por um arco com a mesma direção. Circuito é um
caminho direcionado fechado.
Caminho Simples
Ciclo
É o caminho simples tal que o vértice inicial é igual ao vértice final, onde
v1, v2, ..., vk, vk+1 ∈ V e v1 = vk+1 com k ≥ 3. Diz-se que um grafo é acíclico quando não
possui ciclos simples.
Circuito Euleriano
Subgrafo
1 4
Árvore
É um grafo conexo acíclico com um vértice designado como a raiz da árvore.
Se esta por sua vez for desconexa, então se tem uma floresta. Uma árvore é um dos
tipos mais simples de grafo, e possui diversas propriedades, como é mostrado no
teorema a seguir:
88
bi = 0 se o vértice i é um vértice de
transbordo (transshipment)
A função objetivo é:
n n
Min Z = ∑ ∑ cij xij
i =1 j =1
s.a.
n
n n
∑ xij ⇒ fluxo sai nó i;
j =1
∑ xij − ∑ x ji = bi , ∀i ∈ V
n
x ⇒ fluxo chega nó i;
j =1 j =1
∑ ji
j =1
0 ≤ xij ≤ uij , ∀(i, j ) ∈ A.
Em algumas aplicações, faz-se necessário ter um limite inferior lij > 0 para o
fluxo no arco (i, j). Para evitar alterações na formulação do modelo, utiliza-se:
Uma condição necessária para um PFCM ter alguma solução viável é que
n
∑ bi = 0 , isto é, o fluxo total gerado nos vértices de oferta deve ser igual ao fluxo total
i =1
absorvido nos vértices de demanda. Quando este fato é violado se pode interpretar
como que as ofertas ou as demandas representam limites superiores ao invés de
quantidades exatas. Por exemplo, no caso do Problema de Transporte, um destino
(origem) auxiliar é criado a fim de absorver a oferta (demanda) em excesso. De maneira
análoga, no PFCM cria-se um vértice de demanda (oferta) auxiliar para absorver a
oferta (demanda) em excesso.
A seguir, para exemplificar, é ilustrado na fig. 3A um grafo orientado (digrafo)
representando uma rede de distribuição de uma companhia, onde os vértices 1 e 2 são
duas fábricas desta companhia, com suas respectivas ofertas, os vértices 4 e 5 são dois
estoques, com suas respectivas demandas e o vértice 3 é um centro de distribuição
(transshipment), além dos custos unitários e capacidade de fluxo de alguns arcos, antes
da solução do PFCM e após a solução com suas respectivas distribuições de fluxo.
Figura 3A – Digrafo original com ofertas/demandas nos vértices e seu grafo solução
após resolver o PFCM.
Observe que toda a demanda é atendida pelo fluxo ofertado de forma que o
custo total para realizar esta tarefa é o mínimo possível.
91
APÊNDICE B
E 7 D
10
A 6 15 12
10
B C
11
Figura 1B – Grafo direcionado euleriano (simétrico).
A B C D E
E A D B B
C E D
Ordem 1º 2º 3º 4º 5º 6º 7º 8º FIM
Vértice A
92
A B C D E
E A D B B
C E D
Ordem 1º 2º 3º 4º 5º 6º 7º 8º FIM
Vértice A E
Retornando ao PASSO 2, w ← B pois o arco (E, B) ainda não foi usado. O arco (E, B) é
rotulado como usado, “B” é eliminado do 1º quadro e registrado no 2º quadro, na 1º
posição vazia de T (3º ordem) conforme o PASSO 3. V0 ← B:
A B C D E
E A D B B
C E D
Ordem 1º 2º 3º 4º 5º 6º 7º 8º FIM
Vértice A E B
93
Retornando ao PASSO 2, w ← A, pois (B, A) ainda não foi usado. O arco (B, A) é
rotulado como usado, “A” é eliminado do 1º quadro e registrado no 2º quadro, na 1º
posição vazia de T (4º ordem) conforme o PASSO 3. V0 ← A:
A B C D E
E A D B B
C E D
Ordem 1º 2º 3º 4º 5º 6º 7º 8º FIM
Vértice A E B A
Ao retornar ao PASSO 2, verifica-se que o vértice “A” não tem sucessores, e ainda
existem arcos não usados (vértices não tachados). Ocorre, que se estabeleceu
prematuramente o “circuito parasita” A, E, B, A. Estando no PASSO 4, desloque “A”
para a última casa livre do 2º quadro (FIM do vetor T). O “último” vértice do circuito
agora é “B” (3º ordem).
Ordem 1º 2º 3º 4º 5º 6º 7º 8º FIM
Vértice A E B A
Retornando ao PASSO 2, w ← C, pois (B, C) ainda não foi usado. O arco (B, C) é
rotulado como usado, “C” é eliminado do 1º quadro e registrado no 2º quadro, na 1º
posição vazia de T (4º ordem) conforme o PASSO 3. V0 ← C:
A B C D E
E A D B B
C E D
Ordem 1º 2º 3º 4º 5º 6º 7º 8º FIM
Vértice A E B C A
94
Retornando ao PASSO 2, w ← D, pois (C, D) ainda não foi usado. O arco (C, D) é
rotulado como usado, “D” é eliminado do 1º quadro e registrado no 2º quadro, na 1º
posição vazia de T (4º ordem) conforme o PASSO 3. V0 ← D:
A B C D E
E A D B B
C E D
Ordem 1º 2º 3º 4º 5º 6º 7º 8º FIM
Vértice A E B C D A
Retornando ao PASSO 2, w ← B, pois (D, B) ainda não foi usado. O arco (D, B) é
rotulado como usado, “B” é eliminado do 1º quadro e registrado no 2º quadro, na 1º
posição vazia de T (6º ordem) conforme o PASSO 3. V0 ← B:
A B C D E
E A D B B
C E D
Ordem 1º 2º 3º 4º 5º 6º 7º 8º FIM
Vértice A E B C D B A
Novamente, ao retornar ao PASSO 2, verifica-se que o vértice “B” não tem sucessores,
e ainda existem arcos não usados (vértices não tachados). Ocorre que se estabeleceu
prematuramente o “circuito parasita” B, C, D, B. Estando no PASSO 4, desloque “B’
para a última casa livre do 2º quadro (8º ordem do vetor T). O “último” vértice do circuito
agora é “D” (5º ordem).
Ordem 1º 2º 3º 4º 5º 6º 7º 8º FIM
Vértice A E B C D B A
95
Retornando ao PASSO 2, w ← E, pois (D, E) ainda não foi usado. O arco (D, E) é
rotulado como usado, “E” é eliminado do 1º quadro e registrado no 2º quadro, na 1º
posição vazia de T (6º ordem) conforme o PASSO 3. V0 ← E:
A B C D E
E A D B B
C E D
Ordem 1º 2º 3º 4º 5º 6º 7º 8º FIM
Vértice A E B C D E B A
Retornando ao PASSO 2, w ← D, pois (E, D) ainda não foi usado. O arco (E, D) é
rotulado como usado, “D” é eliminado do 1º quadro e registrado no 2º quadro, na 1º
posição vazia de T (7º ordem) conforme o PASSO 3. V0 ← D:
A B C D E
E A D B B
C E D
Ordem 1º 2º 3º 4º 5º 6º 7º 8º FIM
Vértice A E B C D E D B A
Finalmente, todos os arcos foram usados (vértices tachados). No último quadro tem-se
o circuito de Euler com início e fim no vértice A.
96
APÊNDICE C
{$APPTYPE CONSOLE}
uses
SysUtils;
Const
MAX=400; //Tamanho da lista que armazena o Grafo.
NITER=1000;//Número máximo de iterações.
Type
Tlista= Record
noi:integer;
nof:integer;
custo:integer;
PRT:integer;
end;
Tvetor=Record
peso:real;
noinicial:integer;
nofinal:integer;
ind_i:integer;
ind_j:integer;
end;
TArvore=record
noi:integer;
nof:integer;
custo:integer;
fluxo:integer;
prt:integer;
end;
Tcirc=array of integer;
TTArvore=array of TArvore;//Array dinâmico!!
TLCR=array of Tvetor;
TTLista=array[1..MAX] of Tlista;
TOF_DM=array of integer;
TTime=type TDateTime;
TMatCusto=array of array of integer;
TPred=array of integer;
var
MelhorRota,CircEuler:Tcirc;
Arvore:TTArvore;
Lista:TTLista;//Armazena Grafo G=(V,A,E)
OF_DM:TOF_DM; //Armazena os graus(di's) dos vértices
LCR:TLCR; //Lista de Candidatos Restrita.
U,iter,i,j,Pos,Res,noi,nof,ind,v,k,Dist,MelhorDist,Custo,Temp,no,
alfa:integer;
Local:string;
Tempo:TTime;
MatCusto:TMatCusto;
Pred:TPred;
97
//////////////////////////////////////////////////////////////////////////////
Function modulo(x,y:integer):integer;
var z:integer;
begin
z:=x+y;
if z>0 then
modulo:=z
else
modulo:=-z;
end;
//////////////////////////////////////////////////////////////////////////////
Function modulo1(x,y:integer):integer;
var z:integer;
begin
z:=x-y;
if z>0 then
modulo1:=z
else
modulo1:=-z;
end;
//////////////////////////////////////////////////////////////////////////////
Function Qaresta(var Lista:TTlista):integer;
var x,LJ1,LJ2,i,j:integer;
begin
x:=0;
for i:=1 to k-1 do
for j:=i+1 to k do
begin
LJ1:= Lista[j].noi;
LJ2:= Lista[j].nof;
if (Lista[i].noi=LJ2) and (Lista[i].nof=LJ1) Then
if (Lista[i].PRT<>-1) and (Lista[j].PRT<>-1) Then
inc(x,1);
end;
Qaresta:=x;
end; //Fim do Procedimento
//////////////////////////////////////////////////////////////////////////////
Procedure ComputaPesos(Q:integer); {calcula os pesos w(i,j) das arestas}
var noi,nof,i,j,pos:integer;
begin
pos:=0;
while pos<Q do // troquei Qaresta(Lista) por Q...
begin
for i:=1 to k-1 do
for j:=i+1 to k do
begin
if (lista[i].noi=lista[j].nof) and (lista[i].nof=lista[j].noi) then
{se uma aresta foi encontrada, calcula-se seu peso(w)}
begin
if (lista[i].PRT<>-1) and (lista[j].PRT<>-1) then
98
begin
noi:=lista[i].noi;
nof:=lista[i].nof;
if (OF_DM[noi-1]*OF_DM[nof-1])>0 then
begin
LCR[Pos].peso:=-modulo(OF_DM[noi-1],OF_DM[nof-1]);
LCR[Pos].noinicial:=noi;
LCR[Pos].nofinal:=nof;
LCR[Pos].ind_i:=i;
LCR[Pos].ind_j:=j;
end
else
if (OF_DM[noi-1]*OF_DM[nof-1])<0 then
begin
LCR[Pos].peso:=modulo1(OF_DM[noi-1],OF_DM[nof-1]);
LCR[Pos].noinicial:=noi;
LCR[Pos].nofinal:=nof;
LCR[Pos].ind_i:=i;
LCR[Pos].ind_j:=j;
end
else
if (OF_DM[noi-1]=0) and (OF_DM[nof-1]=0) then
begin
LCR[Pos].peso:=-0.001;
LCR[Pos].noinicial:=noi;
LCR[Pos].nofinal:=nof;
LCR[Pos].ind_i:=i;
LCR[Pos].ind_j:=j;
end
else
if (OF_DM[noi-1]=0) or (OF_DM[nof-1]=0) then
begin
LCR[Pos].peso:=0.001;
LCR[Pos].noinicial:=noi;
LCR[Pos].nofinal:=nof;
LCR[Pos].ind_i:=i;
LCR[Pos].ind_j:=j;
end;
inc(pos);
end;
end;
end;
end;{final do while}
end;
//////////////////////////////////////////////////////////////////////////////
Procedure CalculaOfertaDemanda(var lista:TTlista;no:integer;var OF_DM:TOF_DM);
inc(arc_o)
else
if (lista[i].nof=node) and (lista[i].PRT<>-1) then
inc(arc_i);
end;
grau:=(arc_i)-(arc_o);
OF_DM[node-1]:=grau;
arc_o:=0; arc_i:=0;
inc(node);
end;{fim do while}
end;{fim do procedimento}
//////////////////////////////////////////////////////////////////////////////
Procedure OrdenaLCR(var C:TLCR; n:integer);{ordena a LCR utilizando inserção
direta}
//////////////////////////////////////////////////////////////////////////////
Procedure IncrementaLista(var Lista:TTLista;var Arvore:TTArvore; var
ind:integer);
var i,pos:integer;
begin
ind:=k;
for i:=0 to High(Arvore) do
begin
if ((Arvore[i].fluxo) > 0) then
begin
pos:=ind+(Arvore[i].fluxo);
while (ind < pos) do
begin
inc(ind);
Lista[ind].noi:=Arvore[i].noi;
Lista[ind].nof:=Arvore[i].nof;
Lista[ind].custo:=Arvore[i].custo;
end;
end;
100
end;
end;
//////////////////////////////////////////////////////////////////////////////
Procedure AtualizaLista(var Lista:TTLista);
var i:integer;
begin
For i:=(k+1) to max do
begin
Lista[i].noi:=0;
Lista[i].nof:=0;
Lista[i].custo:=0;
Lista[i].prt:=0;
end;
end;
//////////////////////////////////////////////////////////////////////////////
Procedure CircuitoEuleriano(var Lista:TTLista;V,A,Orig:integer;var CircEuler:
Tcirc;var Dist:integer);
type Clas=^Nodo;
Nodo=record
chave:integer;
prox:Clas;
end;
ListaSuc=array of Clas;
var T:ListaSuc;
ind,no,pos,Valor,TotalArcos,max,i:integer;
//--------------------------------------------------------------------------//
Procedure Ins(var T:Clas;k:integer);
var N,P:Clas;
begin
New(N);
N^.chave:=k;
if T=nil then
begin
N^.prox:=nil;
T:=N;
end
else
begin
P:=T;
while (P^.prox<>nil) do P:=P^.prox;
N^.prox:=P^.prox;
P^.prox:=N;
end;
end;
//--------------------------------------------------------------------------//
Procedure Rem(var T:Clas);
var P:Clas;
begin
P:=T;
T:=T^.prox;
dispose(P);
101
end;
//--------------------------------------------------------------------------//
begin
SetLength(T,V);
TotalArcos:=0;
ind:=1;
Dist:=0;
while (ind<=A) do
begin
Valor:=lista[ind].prt;
if (Valor<>-1) then
begin
Ins(T[(lista[ind].noi)-1],lista[ind].nof);
inc(TotalArcos);
Dist:=(Dist)+(lista[ind].custo);
end;
inc(ind);
end;
max:=TotalArcos+1;
SetLength(CircEuler,max);
no:=Orig;
pos:=0;
CircEuler[pos]:=Orig;
while (TotalArcos>0) do
begin
if (T[no-1]<>nil) then
begin
inc(pos);
i:=no-1;
CircEuler[pos]:=T[no-1]^.chave;
no:=T[no-1]^.chave;
Rem(T[i]);
dec(TotalArcos);
end
else
begin
CircEuler[max-1]:=CircEuler[pos];
CircEuler[pos]:=0;
dec(max);
dec(pos);
no:=CircEuler[pos];
end;
end;
//write('O circuito é: ');
//for i:=0 to High(CircEuler) do
// begin
// write(CircEuler[i],' ,');
// end;
writeln;
writeln;
//write('Custo total: ',Dist);
writeln;
end; //Final do procediemento CircuitoEuleriano!!!
102
//////////////////////////////////////////////////////////////////////////////
Procedure MostrarLista;
var i:integer;
begin
For i:=1 to max do
begin
write(’Lista(’,i,’): ’);
write(’ ’, Lista[i].noi);
write(’-->’,Lista[i].nof);
write(’ ’,Lista[i].custo);
write(’ ’,Lista[i].PRT);
writeln;
end;
end;
//////////////////////////////////////////////////////////////////////////////
Procedure MostrarOF_DM;
var j:integer;
begin
For j:=0 to High(OF_DM) do
write(’Grau’,’(’,j+1,’):’,’-> ’,OF_DM[j],’;’);
end;
const M=10000;
type
regNo=^regPilha;
pilha= regNo;
regPilha=record
no:integer;
prox:pilha;
end;
TLista=record
fluxo:integer;
proxno:integer;
atualno:integer;
end;
VAR
LISTAEL: array of Tlista;
VETORVISITADO,POTN: array of integer;
MATFLUXO:array of array of integer;
MIN,MENORI,MENORJ,J,I:integer;
NOVO,ATUAL,ANT,TOPO:regNO;
IDA,OTIMO:BOOLEAN;
//--------------------------------------------------------------------------//
FUNCTION CICLONEGATIVO: BOOLEAN;
VAR NEGATIVO:BOOLEAN;
ATUALC:PILHA;
BEGIN
103
ATUALC:=TOPO;
NEGATIVO:=TRUE;
WHILE (ATUALC^.PROX<>NIL) AND (NEGATIVO) DO
BEGIN
IF MATFLUXO[ATUALC^.PROX^.NO, ATUALC^.NO]<>1000 THEN
NEGATIVO:=FALSE
ELSE
ATUALC:=ATUALC^.PROX;
END;
CICLONEGATIVO:=NEGATIVO;
END;
//--------------------------------------------------------------------------//
PROCEDURE CONSTROIMATFLUXO;{ESTE PROCEDIMENTO TAMBÉM PRENCHE O VETOR POTN}
VAR L,C,I,NO:INTEGER;
BEGIN
SETLENGTH(MATFLUXO,N+1,N+1);
SETLENGTH(POTN,N);
//WRITELN(’============ CONSTRUINDO A MATRIZ DE FLUXO ============’);
FOR L:=1 TO N DO
FOR C:=1 TO N DO
BEGIN
MATFLUXO[L,C]:=1000;
END;
I:=1;
POTN[0]:=0;
FOR NO:=2 TO N DO
BEGIN
IF (LISTA[I].NOI=1) AND (LISTA[I].NOF=NO) THEN
BEGIN
IF OF_DM[NO-1]<=0 THEN
BEGIN
MATFLUXO[1,NO]:=-OF_DM[NO-1];
POTN[NO-1]:=LISTA[I].CUSTO;
INC(I);
END
ELSE
BEGIN
MATFLUXO[NO,1]:=OF_DM[NO-1];
POTN[NO-1]:=-1000;
INC(I);
END;
END
ELSE
IF OF_DM[NO-1]<=0 THEN
BEGIN
MATFLUXO[1,NO]:=-OF_DM[NO-1];
POTN[NO-1]:=1000;
END
ELSE
BEGIN
MATFLUXO[NO,1]:=OF_DM[NO-1];
POTN[NO-1]:=-1000;
END;
END;
END;
104
//--------------------------------------------------------------------------//
PROCEDURE CONSTROIMATCUSTO;
VAR L,C,I:INTEGER;
BEGIN
//WRITELN(’============ CONSTRUINDO A MATRIZ DE CUSTO ============’);
SETLENGTH(MATCUSTO,N+1,N+1);
I:=1;
FOR L:=1 TO N DO
FOR C:=1 TO N DO
BEGIN
IF (LISTA[I].NOI=L) AND (LISTA[I].NOF=C) THEN
BEGIN
MATCUSTO[L,C]:=LISTA[I].CUSTO;
INC(I);
END
ELSE
MATCUSTO[L,C]:=1000;
END;
END;
//--------------------------------------------------------------------------//
PROCEDURE APONTAPRA(TESTE:INTEGER; VAR ACHEIA:BOOLEAN; VAR K:INTEGER);{O
PROCEDIMENTO RECEBE O PARÂMETRO 'TESTE' E DEVOLVE OS PARÂMETROS 'ACHEIA' E
'K'}
VAR C:INTEGER;
BEGIN
K:=1;
C:=TESTE;
ACHEIA:=FALSE;
WHILE (K<=N) AND (ACHEIA=FALSE) DO
BEGIN
IF (MATFLUXO[K,C]<>1000) THEN
IF (VETORVISITADO[K-1]=0) THEN
ACHEIA:=TRUE
ELSE
INC(K)
ELSE
INC(K);
END;
END;
//--------------------------------------------------------------------------//
PROCEDURE MOSTRARVETARV;
VAR IND:INTEGER;
BEGIN
WRITELN(’=== VETOR ARVORE ===’);
FOR IND:=0 TO HIGH(ARVORE) DO
WRITELN(ARVORE[IND].NOI,’-->’,ARVORE[IND].NOF,’ : ’,ARVORE[IND].CUSTO,’
: ’,ARVORE[IND].FLUXO,’ : ’,ARVORE[IND].PRT);
END;
//--------------------------------------------------------------------------//
PROCEDURE INICIALIZAVISITADO;
SETLENGTH(VETORVISITADO,N);
FOR IND:=0 TO HIGH(VETORVISITADO) DO
VETORVISITADO[IND]:=0;
END;
//-------------------------------------------------------------------------//
PROCEDURE QUALCAMINHO(Q:INTEGER; VAR ACHEIQ:BOOLEAN; VAR C:INTEGER);{O
PROCEDIMENTO RECEBE O PARÂMETRO 'Q' E DEVOLVE OS PARÂMETROS 'ACHEIQ' E 'C'}
VAR K:INTEGER;
BEGIN
K:=Q;
C:=1;
ACHEIQ:=FALSE;
WHILE (C<=N) AND (ACHEIQ=FALSE) DO
BEGIN
IF (K<>C) THEN
IF (MATFLUXO[K,C]<>1000) THEN
IF (VETORVISITADO[C-1]=0) THEN
ACHEIQ:=TRUE
ELSE
INC(C)
ELSE
INC(C)
ELSE
INC(C);
END;
END;
//--------------------------------------------------------------------------//
FUNCTION CONTPILHA(EL:INTEGER):INTEGER; //CONTA O Nº DE ELEMENTOS DA PILHA
BEGIN
ATUAL:=TOPO;
WHILE (ATUAL<>NIL) DO
BEGIN
INC(EL);
ATUAL:=ATUAL^.PROX;
END;
CONTPILHA:=EL;
END;
//--------------------------------------------------------------------------//
PROCEDURE MARCAR(M:INTEGER);
BEGIN
VETORVISITADO[M-1]:=1;
END;
//--------------------------------------------------------------------------//
PROCEDURE GUARDAR(X:INTEGER);
BEGIN
NEW(NOVO);
NOVO^.NO:=X;
IF TOPO=NIL THEN
BEGIN
ANT:=TOPO;
TOPO:=NOVO;
106
TOPO^.PROX:=NIL;
ANT:=NIL;
END
ELSE
BEGIN
NOVO^.PROX:=TOPO;
ANT:=TOPO;
TOPO:=NOVO;
END;
MARCAR(X);
END;
//--------------------------------------------------------------------------//
PROCEDURE CRIACICLO(NO:INTEGER);
VAR ACHEIA,ACHEIQ:BOOLEAN;
K,C:INTEGER;
BEGIN
IF (NO<>J) THEN
BEGIN
APONTAPRA(NO,ACHEIA,K);
IF (ACHEIA) THEN
BEGIN
IF (TOPO=NIL) OR (NO<>TOPO^.NO) THEN GUARDAR(NO);
IDA:=TRUE;
CRIACICLO(K);
END
ELSE
BEGIN
QUALCAMINHO(NO,ACHEIQ,C);
IF (ACHEIQ) THEN
BEGIN
IF (TOPO=NIL) OR (NO<>TOPO^.NO) THEN GUARDAR(NO);
IDA:=TRUE;
CRIACICLO(C);
END;
END;
IF (NOT ACHEIA) AND (NOT ACHEIQ) AND (IDA) THEN
BEGIN
IDA:=FALSE;
MARCAR(NO);
CRIACICLO(TOPO^.NO);
END
ELSE
IF (NOT ACHEIA) AND (NOT ACHEIQ) AND (NOT IDA) THEN
BEGIN
DISPOSE(TOPO);
TOPO:=ANT;
ANT:=TOPO^.PROX;
IDA:=FALSE;
MARCAR(NO);
CRIACICLO(TOPO^.NO);
END;
END
ELSE GUARDAR(NO);
END;
107
//--------------------------------------------------------------------------//
PROCEDURE DESALOCAPILHA;
BEGIN
ATUAL:=TOPO;
WHILE (ATUAL<>NIL) DO
BEGIN
TOPO:=ATUAL^.prox;
DISPOSE(ATUAL);
ATUAL:=TOPO;
END;
END;
//--------------------------------------------------------------------------//
PROCEDURE CALCUSTOREDUZIDO;
CONST BIG=1000;
VAR MENOR,VALOR,L,C:INTEGER;
BEGIN
MENOR:=BIG;
FOR L:=1 TO N DO
FOR C:=1 TO N DO
BEGIN
IF (L<>C) THEN
BEGIN
IF (MATCUSTO[L,C]<>BIG) AND(MATFLUXO[L,C]=BIG) THEN
BEGIN
VALOR:=(POTN[L-1])-(POTN[C-1])+(MATCUSTO[L,C]);
IF (VALOR<MENOR) THEN
BEGIN
MENOR:=VALOR;
MENORI:=L;
MENORJ:=C;
END;
END;
END;
END;
IF (MENOR>=0) THEN OTIMO:=TRUE;
END;
//--------------------------------------------------------------------------//
PROCEDURE MOSTRARMATFLUXO;
VAR L,C:INTEGER;
BEGIN
FOR L:=1 TO N DO
BEGIN
WRITELN;
FOR C:=1 TO N DO
WRITE(MATFLUXO[L,C],’ ’);
END;
WRITELN;
END;
//--------------------------------------------------------------------------//
PROCEDURE MOSTRARMATCUSTO;
108
VAR C,L:INTEGER;
BEGIN
FOR L:=1 TO N DO
BEGIN
WRITELN;
FOR C:=1 TO N DO
WRITE(MATCUSTO[L,C],’ ’);
END;
WRITELN;
END;
//--------------------------------------------------------------------------//
PROCEDURE CONSTROISOLBASICA;
VAR L,C,I:INTEGER;
BEGIN
I:=0;
FOR L:=1 TO N DO
FOR C:=1 TO N DO
IF MATFLUXO[L,C]<>1000 THEN
BEGIN
ARVORE[I].NOI:=L;
ARVORE[I].NOF:=C;
ARVORE[I].CUSTO:=MATCUSTO[L,C];
ARVORE[I].FLUXO:=MATFLUXO[L,C];
ARVORE[I].PRT:=0;
INC(I);
END;
END;
//--------------------------------------------------------------------------//
PROCEDURE MOSTRARPOTN;
VAR IND:INTEGER;
BEGIN
FOR IND:=0 TO N-1 DO WRITE(POTN[IND],’ ’);
END;
//--------------------------------------------------------------------------//
PROCEDURE INICIALIZAPOTN;
VAR I:INTEGER;
BEGIN
POTN[0]:=0;
FOR I:=1 TO (N-1) DO
POTN[I]:=9999;
END;
//--------------------------------------------------------------------------//
PROCEDURE ATUALIZANDOPOTN;{ATUALIZA AS VARIÁVEIS DUAIS DOS VÉRTICES QUE FORMAM
A ÁRVORE BÁSICA}
LABEL INICIO;
VAR I:INTEGER;
BEGIN
INICIALIZAPOTN;
I:=0;
WHILE I <= HIGH(ARVORE) DO
INICIO:
109
BEGIN
IF (ARVORE[I].NOI=1) AND (ARVORE[I].PRT<>-1) THEN
BEGIN
POTN[(ARVORE[I].NOF)-1]:=(POTN[(ARVORE[I].NOI)- 1])
+(MATCUSTO[ARVORE[I].NOI,ARVORE[I].NOF]);
ARVORE[I].PRT:=-1;
END;
//--------------------------------------------------------------------------//
PROCEDURE INICIALISTAEL; {INICIALIZA O VETOR QUE IRÁ ARMAZENAR O VALOR DO
FLUXO DAS ARESTAS CONTRÁRIAS AO ARCO ENTRANTE NO CILCO FORMADO PELO MESMO}
VAR I:INTEGER;
BEGIN
SETLENGTH(LISTAEL,N);
FOR I:=0 TO HIGH(LISTAEL) DO
BEGIN
LISTAEL[I].FLUXO:=-1;
LISTAEL[I].PROXNO:=0;
LISTAEL[I].ATUALNO:=0;
END;
END;
//--------------------------------------------------------------------------//
PROCEDURE MINIMO;{CALCULA O MENOR FLUXO DENTE OS ARCOS CONTRÁRIOS AO ARCO
ENTRANTE}
110
BEGIN
ATUAL:=TOPO;
MIN:=1000;
WHILE ATUAL^.PROX<>NIL DO
BEGIN
IF MATFLUXO[ATUAL^.PROX^.NO, ATUAL^.NO]<>1000 THEN
IF MATFLUXO[ATUAL^.PROX^.NO, ATUAL^.NO]< MIN THEN
MIN:=MATFLUXO[ATUAL^.PROX^.NO, ATUAL^.NO];
ATUAL:=ATUAL^.PROX;
END;
END;
//--------------------------------------------------------------------------//
PROCEDURE ATUALIZAMATFLUXO;
VAR POS,P:INTEGER;
BEGIN
INICIALISTAEL;
MINIMO;
MATFLUXO[I,J]:=MIN;
ATUAL:=TOPO;
POS:=0;
WHILE (ATUAL^.PROX<>NIL) DO
BEGIN
IF MATFLUXO[ATUAL^.NO, ATUAL^.PROX^.NO]=1000 THEN
BEGIN
MATFLUXO[ATUAL^.PROX^.NO, ATUAL^.NO]:=
MATFLUXO[ATUAL^.PROX^.NO,ATUAL^.NO]- MIN;
LISTAEL[POS].FLUXO:=MATFLUXO[ATUAL^.PROX^.NO, ATUAL^.NO];
LISTAEL[POS].PROXNO:=ATUAL^.PROX^.NO;
LISTAEL[POS].ATUALNO:=ATUAL^.NO;
INC(POS);
END
ELSE
MATFLUXO[ATUAL^.NO, ATUAL^.PROX^.NO]:= MATFLUXO[ATUAL^.NO,
ATUAL^.PROX^.NO]+ MIN;
ATUAL:=ATUAL^.PROX;
END;
FOR P:=0 TO (CONTPILHA(0)-2) DO {CASO HAJA MAIS DE UM ARCO COM FLUXO
ZERO, O PRIMEIRO ARCO DA LISTA RECEBERÁ FLUXO 1000 NA MATFLUXO. ISTO É, SAIRÁ
DA ÁRVORE}
IF (LISTAEL[P].FLUXO=0) THEN
BEGIN
MATFLUXO[LISTAEL[P].PROXNO,LISTAEL[P].ATUALNO]:=1000;
BREAK;
END;
END;
///////////////////////// CHAMADA DOS PROCEDIMENTOS ////////////////////////
BEGIN
{=============== OTIMIZANDO OS FLUXOS ===============}
CONSTROIMATFLUXO;
CONSTROIMATCUSTO;
CONSTROISOLBASICA;
INICIALIZAVISITADO;{OBTEM UMA ÁRVORE BÁSICA INICIAL}
OTIMO:=FALSE;
TOPO:=NIL;
WHILE (NOT OTIMO) DO
111
BEGIN
CALCUSTOREDUZIDO;
IF (NOT OTIMO) THEN
BEGIN
I:=MENORI;
J:=MENORJ;
IF TOPO<>NIL THEN DESALOCAPILHA;
CRIACICLO(I);
IF (CICLONEGATIVO) THEN
BEGIN
WRITELN(’CICLO NEGATIVO!!! = <<FIM DO PROGRAMA>>’);
READLN;
HALT;{ENCERRA O PROGRAMA!!!!}
END
ELSE
BEGIN
ATUALIZAMATFLUXO;
//WRITELN(’==========STATUS==========’);
//WRITELN(’== MATRIZ DE FLUXO ==’);
//MOSTRARMATFLUXO;
CONSTROISOLBASICA;{ATUALIZA A ARVORE!!}
ATUALIZANDOPOTN;
//WRITELN;
//MOSTRARVETARV;
//WRITELN(’== POTENCIAS DOS NOS ==’);
//MOSTRARPOTN;
INICIALIZAVISITADO;
END;
END;
END;
//WRITELN(’========================== FINAL =======================’);
//WRITELN(’== MATRIZ DE FLUXO ==’);
//MOSTRARMATFLUXO;
//WRITELN;
//WRITELN (’== MATRIZ DE CUSTO ==’);
//MOSTRARMATCUSTO;
//WRITELN;
//MOSTRARVETARV;
//READLN;
END;
var pos:integer;
melhoria:boolean;
begin
melhoria:=true;
pos:=0;
while (melhoria) and (pos<=High(Arvore)) do
begin
If pos<>i then
begin
if (Arvore[i].noi<>Arvore[pos].noi) and
(Arvore[i].noi<>Arvore[pos].nof) then
begin
if (Arvore[i].nof<>Arvore[pos].noi) and
(Arvore[i].nof<>Arvore[pos].nof) then
112
inc(pos)
else
if Arvore[pos].fluxo<>0 then
melhoria:=False
else
inc(pos);
end
else
if Arvore[pos].fluxo<>0 then
melhoria:=false
else
inc(pos);
end
else
inc(pos);
end;//Fim do while
PodeMelhorar:=Melhoria;
end;
//////////////////////////////////////////////////////////////////////////////
Procedure Dijkstra(var W:TMatCusto;n,s,t:integer;var Custo:integer;
var Pred:TPred);
Type
arrn=array of integer;
boolarrn=array of boolean;
Var
j,u,v,y,recent:integer;
newlabel,temp:integer;
path:boolean;
final:boolarrn;
dist:arrn;
Begin
SetLength(Dist,n+1);
SetLength(Pred,n+1);
SetLength(Final,n+1);
For v:=1 to n do
begin
dist[v]:=1000;{peso do arco}
final[v]:=false;{arco não existente}
pred[v]:=-1;
end;
dist[s]:=0;
final[s]:=true;
path:= true;
recent:= s;
while (not final[t]) do
begin
for v:=1 to n do {encontra um novo rótulo}
if (W[recent,v]<1000) and (not final[v]) then
begin
newlabel:=dist[recent] + W[recent,v];
if newlabel<dist[v] then
begin
dist[v]:=newlabel;
pred[v]:=recent;
end;
end;
113
temp:=1000;
for u:=1 to n do {encontra um menor vértice rotulado}
if (not final[u]) and (dist[u]<temp) then
begin
y:=u;
temp:=dist[u];
end;
if (temp < 1000) then {existe um caminho}
begin
final[y]:=true;
recent:=y;
end
else {não existe caminho de s para t}
begin
path:=false;
final[t]:=true;
end;
end; {while}
Custo:=Dist[t];
writeln;
{writeln(’Custo :’,custo);
write(’DIST:’,’[’);
For j:=1 to n do
begin
write(Dist[j],’,’);
end;
writeln(’]’);
writeln;
write(’PRED:’,’[’);
For j:=1 to n do
begin
write(Pred[j],’,’);
end;
writeln(’]’);
readln;}
end;
//////////////////////////////////////////////////////////////////////////////
Procedure LerArquivo(var Lista:TTLista; Local:string);
Var
Arq:TextFile;
Noi,Nof,Custo,ind:integer;
begin
AssignFile(Arq,Local);
Reset(Arq);
ind:=0;
while not EOF(arq) do
begin
inc(ind);
readln(Arq,noi,nof,custo);
lista[ind].noi:=noi;
lista[ind].nof:=nof;
lista[ind].custo:=custo;
end;
Close(Arq);
end;
writeln(’=======================INICIO DO PROGRAMA=========================’);
write(’Selecione o grafo: ’);
readln(Local);
LerArquivo(Lista,Local);
write(’Numero de nos: ’);
readln(v);
writeln;
write(’Numero de arcos: ’);
readln(k);
writeln;
write(’Selecione um vertice inicial: ’);
readln(no);
writeln;
write(’Entre com o parametro alfa: ’);
readln(alfa);
SetLength(Arvore,v-1);
SetLength(LCR,Qaresta(Lista));
SetLength(OF_DM,v);
//-------------------------FASE DE CONSTRUÇÃO-------------------------------//
iter:=1;
MelhorDist:=10000;
Tempo:=Now();
while (iter<=NITER) do
begin
U:=Qaresta(Lista);
CalculaOfertaDemanda(lista,v,OF_DM);;
ComputaPesos(U);{Preenche a LCR}
OrdenaLCR(LCR,U);
while U <> 0 do {enquanto houver arestas na LCR para serem orientadas}
begin
Randomize;
If U >= alfa then
Pos:=Random(alfa)
else
Pos:=Random(U);
noi:=LCR[Pos].noinicial;
nof:=LCR[Pos].nofinal;
If (OF_DM[noi-1] > OF_DM[nof-1]) then
Lista[LCR[Pos].ind_j].PRT:=-1
else
If (OF_DM[noi-1]=OF_DM[nof-1]) then
begin
Randomize;
Res:=Random(2);
If Res=0 then
Lista[LCR[Pos].ind_i].PRT:=-1
else
Lista[LCR[Pos].ind_j].PRT:=-1
end
else
Lista[LCR[Pos].ind_i].PRT:=-1;
Dec(U);
CalculaOfertaDemanda(lista,v,OF_DM);
ComputaPesos(U);{Preenche a LCR}
OrdenaLCR(LCR,U);
end; {Final do while}
CalculaOfertaDemanda(lista,v,OF_DM);
115
FluxoCustoMinimo(LISTA,OF_DM,ARVORE,MATCUSTO,v);
IncrementaLista(Lista,Arvore,ind);
CircuitoEuleriano(Lista,v,ind,no,CircEuler,Dist);
//----------------------------FASE DE MELHORIA------------------------------//
For i:=0 to High(Arvore) do
If (Arvore[i].fluxo<>0) and (PodeMelhorar(i)) then//caso encontre arcos
isolados,ie, sem outros arcos adjacentes....
begin
Dijkstra(MatCusto,v,Arvore[i].noi,Arvore[i].nof,Custo,Pred);
if (Custo<Arvore[i].custo) then//efetuará o procedimento de troca.
begin
For j:=1 to ind do
begin
If (Lista[j].noi=Arvore[i].noi) and Lista[j].nof=Arvore[i].nof)
then Lista[j].prt:=-1;
end;
nof:=Arvore[i].nof;
noi:=Pred[nof];
while noi<>-1 do
begin
Temp:=Arvore[i].fluxo;
repeat
inc(ind);
Lista[ind].noi:=noi;
Lista[ind].nof:=nof;
Lista[ind].custo:=Arvore[i].custo;
dec(Temp);
until Temp=0;
nof:=noi;
noi:=Pred[nof];
end;
writeln(’============MELHORIA EFETUADA!!!!============’);
writeln('============O NOVO CICLO SERÁ.....===========');
CircuitoEuleriano(Lista,v,ind,no,CircEuler,Dist);
readln;
end;
end;
//--------------------------------TESTE FINAL-------------------------------//
if (Dist < MelhorDist) then
begin
MelhorDist:=Dist;
MelhorRota:=CircEuler;
end;
for i:=1 to ind do lista[i].prt:=0;
writeln('Iteracao:',iter);
writeln;
inc(iter);
end;
Tempo:=Now()-Tempo;
write('Melhor Custo Z(T): ',MelhorDist);
writeln;
writeln;
write('Melhor Rota: ');
for i:=0 to High(MelhorRota) do
begin
write(MelhorRota[i],' ,');
end;
116
writeln;
writeln;
write(’Tempo Total: ’,TimeToSTR(Tempo));
readln;
end.