Anais do 13O Encontro de Iniciação Científica e Pós-Graduação do ITA – XIII ENCITA / 2007 Instituto Tecnológico de Aeronáutica, São José dos Campos, SP, Brasil, Outubro, 01 a 04, 2007. ALGORITMOS DE OTIMIZAÇÃO COMBINATÓRIA Henry Wei Cheng Hsu Instituto Tecnológico de Aeronáutica, Praça Marechal Eduardo Gomes, 50 -Vila das Acácias – S. J. dos Campos Bolsista PIBIC-CNPq [email protected] Nei Yoshiriro Soma Instituto Tecnológico de Aeronáutica, Praça Marechal Eduardo Gomes, 50 -Vila das Acácias – S. J. dos Campos [email protected] Resumo. O artigo apresentará diversas situações em que os algoritmos de otimização combinatória se mostram de especial utilidade. Além disso será apresentada a modelagem de problemas, uma tarefa de extrema importancia que muitas vezes necessita de grande criativadade. Palavras chave: Algoritmo, Otimização ,Combinatória ,Grafo, Programação Dinâmica 1. Introdução Os algoritmos de otimização combinatória se mostram de extrema importância para a computação. Eles permitem a análise e otimização de situações em um número muito grande de áreas de aplicação. Alguns poucos exemplos são: redes sociais, mapeamento genético, rotas de aviação, sistemas de comunicação, gerenciamento de estoque, bancos de dados, entre muitos outros. Nessa iniciação científica, propôs-se o estudo de algoritmos que abrangem a teoria dos grafos, programação dinâmica e teoria dos números. Além disso, foi necessária uma familiarização com linguagens de programação e com estrutura de dados. No decorrer do ano letivo da iniciação científica houve muito progresso nos estudos e implementação de algoritmos. Ocorreu o estudo teórico de algoritmos nas áreas de teoria dos grafos, programação dinâmica, e teoria dos números. Além disso, houve muita prática na implementação de algoritmos e também uma atividade muito importante que é a modelagem e resolução de problemas de diversas áreas através de algoritmos de otimização. Uma atividade paralela altamente proveitosa é a participação na “ACM Internacional Collegiate Programming Contest”. Junto com os alunos de graduação do Instituto Tecnológico de Aeronáutica Hélder Suzuki e Cesário Martins, foi formado uma equipe para a participação nessa competição. A preparação para o evento envolveu reuniões semanais, a resolução e implementação de dezenas de questões de competições passadas, disponíveis no web site http://acm.uva.es [5], além do estudo de algoritmos, de técnicas de resolução e da utilização da criatividade para a resolução de problemas. É de extrema importância o conhecimento dos algoritmos de otimização. No entanto, em diversas apliações apenas o uso destes algoritmos não é suficiente. É necessário antes modelar a situação e adaptá-la para o uso de algoritmos conhecidos. Essa tarefa, na maioria das vezes, é bastante difícil. Justamente por esse motivo, ela se torna a mais interessante e a mais intrigante para os estudiosos de computação. Nesse relatório serão apresentadas pequenas situações a serem solucionadas. Algoritmos de otimazação serão utilizados. Porém o enfoque da solução será nas idéias utilizadas para a modelagem da questão. Após a descrição de cada situação será feito um breve comentário. Em seguida será apresentada a solução, estas contendo idéias que as tornam belas e elegantes. 2.Situação Uma indústria fabrica copos plásticos de três tamanhos (pequeno, médio e grande) e os vende em diferentes tipos de pacotes. Cada tipo de pacote é identificado por três inteiros positivos (S1, S2, S3) em que Si denota a quantidade de copos de tamanho i no pacote. No entanto, nunca ocorre S1 =S2 =S3. Deseja-se juntar uma quantidade de pacotes tal que exista o mesmo número de copos dos três tamanhos. Por exemplo, se houver 4 tipos de pacotes: (1, 2, 3), (1, 11, 5), (9, 4, 3) e (2, 3, 2). É possível juntar três pacotes do tipo (1, 2, 3), um do tipo (9, 4, 3) e dois do tipo (2, 3, 2). Dessa forma obtém-se 16 copos de cada tipo. Dadas a quantidade de tipos de pacotes e as suas configurações, deseja-se determinar se é possível obter a mesma quantidade de copos dos três tamanhos. 2.1.Comentário A princípio a questão se encaixa na área de Teoria dos Números. No entanto a resolução apresentada a seguir toma outro caminho, utilizando-se apenas de argumentos geométricos, tornando-a particularmente elegante. Anais do XIII ENCITA 2007, ITA, Outubro, 01-04, 2007 , 2.2.Solução Para cada tripla, considere o par ordenado definido da seguinte forma (S1, S2, S3) → (S2-S1, S3-S1). Obtêm-se os N pares ordenados correspondentes aos trios ordenados iniciais. O problema equivalente torna-se: juntar uma determinada quantidade de pares ordenados de cada tipo para obter o par (0,0) como resultado. Para o prosseguimento da resolução, será feita a definição de fecho convexo. O fecho convexo de um conjunto Q de pontos é o menor polígono convexo P para o qual cada ponto em Q está no limite de P ou em seu interior. Considere cada par ordenado como um vetor no plano R2. Deseja-se saber se é possível somar os vetores (é permitido repetir o mesmo vetor) para que a resultante total seja nula. A seguir será mostrada uma maneira de responder essa questão. Traça-se o fecho convexo dos N pontos. Se a origem estiver no interior do fecho, a resposta da questão é afirmativa, caso contrário a resposta é negativa. Se a origem estiver fora do fecho convexo, é possível traçar uma reta de forma que todos os vetores estão em um mesmo semi-plano definido pela reta. y x Fig 1 – A origem está fora do fecho convexo, logo qualquer resultante dos vetores estará em um dos semi-planos definido acima, portanto a resultante nunca será nula. A resultante pertence ao mesmo semi-plano dos N vetores, portanto nunca é nula. Para o caso em que a origem está contida no fecho convexo deve-se prosseguir da seguinte maneira: escolher três pontos tal que o triângulo formado contém a origem. É possível obter a resultante nula apenas com estes três vetores. (a,b) (0,0) (e,f) (g,h) (c,d) Fig 2 – A origem está contida no triângulo formado pelos pontos (a,b), (c,d) e (e,f) As coordenadas (a,b), (c,d) e (e,f) são inteiras. Por geometria analítica, é fácil verificar que (g,h) possui coordenadas racionais. Adotando pesos racionais para os pontos (c,d) e (e,f) e somando-os é possível obter o ponto (g,h). Multiplicando (g,h) por um peso racional anula-se o vetor (a,b). Logo, é possível escolher pesos racionais para cada um dos vetores (a,b), (c,d) e (e,f) e obter a resultante (0,0). Como conclusão, se a origem está contido no fecho convexo dos N pontos, a resposta do problema é afirmativa. Para passar essa resolução para uma linguagem de programação são necessários dois algoritmos muito importantes. O primeiro é determinar o fecho convexo de um conjunto Q de pontos. O outro é a verificação de um ponto estar contido em um polígono convexo. A seguir será apresentado o pseudo-código dos dois algoritmos. Fecho convexo: A varredura de Graham Anais do XIII ENCITA 2007, ITA, Outubro, 01-04, 2007 , O procedimento mantém uma pilha S de pontos candidatos. A função TOP(S) retorna o ponto no topo da pilha S sem alterar S. NEXT-TO-TOP(S) retorna o ponto no topo da pilha S sem alterar S. GRAHAM-SCAN(Q) 1- Seja p0 o ponto mais à esquerda dentre os pontos em Q com coordenada y mínima 2- Sejam(p1,p2,...,pm) os pontos restantes em Q, ordenados por ângulo polar em ordem da direita para a esquerda em torno de p0 (se mais de um ponto tiver o mesmo ângulo, remova todos eles, exceto o mais afastado de p0) 3- PUSH(p0,S) 4- PUSH(p1,S) 5- PUSH(p2,S) 6- para i←3 até m 7do while o ângulo formado pelos pontos NEXT-TO-TOP(S), TOP(S) e pi formar uma volta não à esquerda 8do POP(S) 9PUSH(pi,S) 10- return (S) Para verificar se um ponto P está contido em um polígono convexo basta seguir o seguinte procedimento: traça-se uma semi-reta horizontal do ponto P ao infinito. Se a semi-reta cruzar o polígono uma única vez, o ponto está contido no polígono. Caso haja dois cruzamentos o ponto está fora do polígono. Como o polígono é convexo, só existem essas duas possibilidades. 3.Situação Existem 2n diferentes sequências de n bits. Encontre uma sequência circular em que todas as sequências de n bits aparecem exatamente uma vez. Por exemplo, para n=2 uma possível resposta é 0011 (pois as subsequências de 2 bits são 00, 01, 11, 10). 3.1.Comentário Esse problema está relacionado com o dígrafo de De Bruijn. Informações interessantes sobre o assunto podem ser encontrado no seguinte site: http://en.wikipedia.org/wiki/De_Bruijn_digraph (acessado em 08/2007) [6]. 3.2.Solução Para a resolução do problema será considerado um grafo auxiliar. Os vértices do grafo são as 2n-1 seqüências de n-1 bits. Uma aresta direcional é traçada quando os últimos n-2 bits do vértice de origem coincidem com os primeiros n-2 bits do vértice de chegada. Em cada aresta é marcado uma seqüência de n bits construída da seguinte forma: o primeiro bit é igual ao primeiro bit do vértice de origem, os próximos n-2 bits são os n-2 bits coincidentes entre os dois vértices e o último bit é igual ao último bit do vértice de chegada. A Fig. 3 ilustra o grafo auxiliar para o caso n=3. Fig. 3 – grafo auxiliar para o caso n=3 É fácil verificar que nas arestas são geradas todas as seqüências de n bits. Outro fato importante é o de que os n-1 bits finais de uma aresta incidente coincidem com os n-1 bits iniciais de uma aresta de saída. A seqüência circular desejada pode ser obtida através da determinação de um ciclo Euleriano (um ciclo que passa por todas as arestas) no grafo auxiliar. Ressalta-se que o ciclo Euleriano sempre existe pelo fato de o grafo de o grafo ser fortemente conexo e todos os vértices possuírem grau-in igual ao grau-out. A seqüência circular é determinada da seguinte forma: Anais do XIII ENCITA 2007, ITA, Outubro, 01-04, 2007 , 1- Tome um vértice qualquer do grafo para começar o traçado de um ciclo Euleriano 2- Caminhe por todos os vértices seguindo um ciclo Euleriano. Para cada vértice visitado, adicione o último bit desse vértice à seqüência. 3- Quando o ciclo terminar temos a seqüência desejada. Uma possível solução para o caso n=3 é 00111010. A seguir será apresentado o algoritmo de determinação do ciclo Euleriano, a fim de que a seqüência circular desejada possa ser obtida com o auxílio de um computador. EULER-TOUR(G) 1- Inicie com um vértice v0 qualquer do grafo G 2- Caminhe sucessivamente pelas arestas de G, deletando cada aresta de G conforme são percorridas. Não percorra, em nenhum ponto particular do procedimento, por uma aresta cuja deleção divide o grafo remanescente de G em duas partes não-vazias. 3- Continue o procedimento até todas as arestas de G serem deletadas, ocasião na qual há o retorno ao vértice v0. 4.Situação Ao se representar um número na base decimal, são necessários os dígitos de 0 a 9. Se apenas um subconjunto dos dígitos decimais for permitido, há apenas uma quantidade limitada de números que pode ser representada. Por exemplo, se apenas os dígitos 1 e 2 forem permitidos, os números 11 e 12 podem ser representados, mas o número 10 não pode. Se os múltiplos de 13 forem listados: 13, 26, 39, ..., 195, 208, 221, etc., percebe-se que 221 é o menor natural que pode ser representado utilizando somente os dígitos 1 e 2. Questão: Encontre o menor múltiplo de um certo número N que pode ser representado utilizando somente um dado subconjunto dos dígitos decimais. Esse múltiplo pode ser o próprio número, mas deve ser maior que zero. Considere N ≤100000. O subconjunto dos dígitos permitidos também é fornecido. 4.1Comentário Uma possível solução para o problema é gerar todos os números formados pelo subconjunto de dígitos dados, e verificar a sua divisibilidade por N. No entanto, esse procedimento toma tempo exponencial. A seguir será apresentada uma bonita solução que se utiliza da teoria dos grafos. 4.2.Solução Considere o número decimal a0a1...ak, em que ai pertence ao subconjunto de dígitos permitidos. Adicione o dígito ak+1 à direita do número. Fatos interessantes: (a0a1...ak ak+1) = 10 (a0a1...ak) + ak+1 e em particular temos, (a0a1...ak ak+1) ≡ 10 (a0a1...ak) + ak+1 (mod N) Tome um grafo cujos vértices são os números de 0 a N-1. O conjunto {b0,..., bp} é o conjunto dos dígitos permitidos. Uma aresta X→Y é traçada se e somente se ∃ i tal que Y ≡ 10X+bi (mod N). X (a0a1...ak) mod N ak+1 Y (a0a1...akak+1) modN Fig. 4 – Ilustração de dois vértices que devem ser unidos por uma aresta No universo dos números naturais módulo N, X representa o número (a0a1...ak) modN e Y o número (a0a1...ak ak+1) mod N. Assim, diz-se que Y é gerado por x através de uma aresta do tipo ak+1. Em um caminho iniciando por um dado vértice, a cada aresta percorrida gera-se um número cuja representação na base decimal possui um dígito a mais. Se o caminho passar pelo vértice 0, obtém-se um número na base decimal cujo resto módulo N é igual a zero. Um pequeno exemplo para ilustração: Seja {1,2} o conjunto de dígitos permitidos e N=13. Um caminho possível é: Anais do XIII ENCITA 2007, ITA, Outubro, 01-04, 2007 , 2 2 2 mod 13 9 22 mod 13 1 0 221 mod 13 Fig. 5 – Ilustração de um caminho possível A partir do vértice 2 caminhando por uma aresta do tipo 2, é gerado o número 22, que é equivalente a 9 no mod 13. De 22 chega-se a 221 por uma aresta do tipo 1. Mas note que 221 é congruente a 0 mod 13. Antes de prosseguir na resolução da questão, abre-se um parêntesis para um breve comentário sobre o algoritmo da busca em largura. O BFS (Breadth First Search – busca em largura em inglês) determina o menor caminho de uma origem a um dado vértice em um grafo não ponderado. Essa busca se mostra muito útil nesse questão, pois procura-se um número com o menor número de dígitos possível. A solução da questão pode ser descrita da seguinte maneira: 1- Montar o grafo cujos vértices são os números de 0 a N-1 2- Traçar as arestas conforme descrito anteriormente 3- Para cada i entre 1 e p, executar um BFS de origem bi e alvo o vértice 0. Tomar cuidado para, durante a rotina, sempre visitar o vizinho cujo tipo de aresta seja o menor possível. Ao encontrar um caminho entre a origem bi e o vértice 0, armazenar o número decimal obtido. 4- A resposta é o menor dentre os números armazenados. O BFS encontra um caminho mínimo entre uma origem e o vértice 0 (caso o vértice 0 seja alcançável a partir dessa origem). Isso significa que o número decimal gerado possui o menor número de dígitos possível. A ordem de escolha dos vizinhos durante a busca permite que o caminho percorrido indique o menor número dentre aqueles com o menor número de arestas. Por fim, basta escolher o menor número dentre os encontrados para cada origem. O algoritmo da Busca em Largura. BFS(G,s) 1- para cada vértice u ε V[G] – {s} do cor[u] ← 0 23- cor[s] ← 1 4- Q ← 0 5- ENQUEUE (Q, s) 6- while Q ≠ 0 do u ← DEQUEUE(Q) 7for cada v ← Adj[u] 89do if cor[v] = 0 then cor[v] ← 1 1011ENQUEUE(Q, v) 12cor[u] ← 2 Anais do XIII ENCITA 2007, ITA, Outubro, 01-04, 2007 , 5.Situação Desja-se colocar peças de torre em um tabuleiro de xadrez n x n, de forma que nenhum par de torres se ataque. Porém, existem algumas casas que estão rachadas, logo não é permitido que nenhuma torre fique nessa casa. Dada as coordenadas das casas rachadas, determinar o maior números de torres que pode-se colocar no tabuleiro. 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 Fig 6 – Tabuleiro de xadrez contendo casas rachadas 5.1.Comentário A solução mais natural para esse problema é a utilização da técnica de backtracking. Porém, o tempo de execução seria exponencial, o que torna inviável a resolução para dimensões do tabuleiro muito grandes. Para essa questão será utilizado um importante algoritmo na teoria dos grafo que é o Network Flow. 5.2.Solução Para a resolução dessa questão é necessária a construção de um grafo de fluxo em rede. Fig 10 – Ilustração de um possível grafo de fluxo em rede para a questão O grafo é formado pelo vértices “torneira”, “ralo”, Hi e Vi (1 ≤ i ≤ n). Traça-se arestas da “torneira” a cada vértice Hi, e arestas de cada Vi ao “ralo”. Traça-se uma aresta entre Hi e Vj se, e somente se a casa (Hi, Vj) do tabuleiro não estiver rachada. Todas as arestas possuem capacidade 1. O fluxo máximo entre a “torneira” e o “ralo” é exatamente a quantidade máxima de torres que podem ser colocadas no tabuleiro. As arestas entre a “torneira” e os vértices Hi têm capacidade 1, implicando que em cada linha horizontal do tabuleiro haja no máximo uma torre. Da mesma maneira, As arestas entre o “ralo” e os vértices Vi indicam que há no máximo uma torre em cada coluna vertical do tabuleiro. Ao término do algoritmo de fluxo máximo, se uma aresta HiVj possuir fluxo 1, então existe uma torre na casa (Hi, Vj) do tabuleiro. Note que uma torre nunca cairá em uma casa rachada pois não exite aresta para essa possibilidade. Anais do XIII ENCITA 2007, ITA, Outubro, 01-04, 2007 , Agora, falta apenas o algoritmo para determinação do fluxo máximo. FORD-FUKERSON(G, s, t) 1- for cada aresta (u, v) ← E[G] 2- do f[u, v] ← 0 3- F[v,u] ← 0 4- while existir um caminho p de s até t na rede residual Gf do cf(p) ← min{cf(u, v) : (u,v) está em p} 5- for cada aresta (u, v) em p 6- do f[u, v] ← f[u, v] + cf(p) 78- f[v,u] ← - f[u, v] 6.Situação Uma indústria fabrica robôs que catam lixo do chão após eventos esportivos. Antes dos robôs entrarem em ação, uma fotografia aérea é tirada e dividida em quadrados. As localizações que contém lixo estão marcadas. Todos o robôs partem do canto noroeste e terminam seu trajeto no canto sudeste. Um robô só pode se movimentar em duas direções, para o Sul e para o Leste. Ao entrar em uma célula contendo lixo, o robô cata-o antes de prosseguir. Uma vez no canto sudeste, o robô não pode ser reposicionado ou reutilizado. A tarefa é encontrar o menor número de robôs necessários para limpar a área inteira. Por exemplo, considere a área mostrada na Fig. 11. As posições dos lixos estão marcadas com a letra ‘G’. Os robôs partem do ponto (1,1) e chegam ao ponto (6,7). Fig 11 – Uma fotografia aérea da área A Fig. 12 mostra duas soluções possíveis. A segunda é melhor pois utiliza dois robôs em vez de três. Fig. 12 – Duas soluções possíveis 6.1.Comentário Para essa questão parede bastante natural pensar em programação dinâmica para a resolução. A seguir será apresentada uma bela solução baseada no algoritmo da maior subseqüência crescente. 6.2.Solução A primeira parte da solução consiste em criar uma seqüência s de naturais da seguinte forma: para cada linha, da primeira à última, transcreva os índices das colunas em que estão as sujeiras. No exemplo mostrado nas figuras anteriores a construção se dá na seguinte forma. Anais do XIII ENCITA 2007, ITA, Outubro, 01-04, 2007 , 1ª linha : 2 4 2ª linha : 4 6 3ª linha : 4ª linha : 4 7 5ª linha : 6ª linha : 6 Seqüência s : 2 4 4 6 4 7 6. Um robô que pegou um pedaço de lixo numa coluna i não pode mais pegar nenhum pedaço de lixo em uma coluna de índice menor do que i, pois ele só pode andar para o leste ou para o sul. Ao tomar uma subseqüência decrescente na seqüência s, temos que para cada elemento dessa subseqüência deve haver um robô. A explicação é justamente o fato de que o robô não pode voltar para uma coluna de índice menor do que a que ele está. Dessa forma, o número de elementos da maior subseqüência decrescente é igual à quantidade de robôs necessários para pegar todos os pedaços de lixo da área. Agora basta apenas o algoritmo de determinação do tamanho da maior subseqüência decrescente de uma seqüência s - a1a2...ak. MAIOR-SUBSEQUÊCIA-DECRESCENTE (s) 1- Defina F(i) como o tamanho da maior subseqüência decrescente entre o início e o índice i da seqüência s. 2- F(0) ← 0, F(1) ← 1 3- for i ← 1 até k 4- do F(i) = max{ F(j) } + 1, para aj ≥ ai e 0 ≤ j ≤ i-1 5- F(k) é o valor desejado 7.Agradecimentos • • • • • • • Aos meus amigos Hélder Suzuki e Cesário Martins pela grande colaboração no estudo de algoritmos e programação À equipe “Sushi, Yakisoba e Forró” pela união e amizade dos membros e pela ótima experiência na participação da Maratona de programação Ao professor Nei Yoshihiro Soma por me orientar nesse trabalho de iniciação científica Ao professor Armando Gouveia por todo o apoio e incentivo ao estudo de programação e algoritmos A Humberto Naves pelas dicas e orientações durante o ano Aos professores Eduardo Tengan, Carlos Shine , Edmilson Motta e Pablo Ganassim pela ótima base matemática que me forneceram Ao CNPq pela oportunidade fornecida de pesquisa e desenvolvimento de um trabalho tão interessante 8. Referências [1] CORMEN, T.H., LEISERSON, C.E., RIVEST, R.L., STEIN, C. Algoritmos-Tradução da 2ª edição americana. Ed. Campus, 2001 [2] JUNGNICKEL, D., Graphs, Networks and Algorithms. Springer, 1999. [3] SEDGEWICK, R., Algorithms. ADDISON-WESLEY, 1984 [4] SKIENA, S.S., REVILLA, M.A., Programming Challenges, Ed. Springer, 2003. [5] International ACM Programming Contest. Disponível em <http://acm.uva.es>. Acesso em 08/2007. De Bruijn digraph. [6] Wikipedia, the free <http://en.wikipedia.org/wiki/De_Bruijn_digraph>. Acesso em agosto de 2007. encyclopedia. Disponível em