You are on page 1of 9

Proposta de Soluo para o Problema dos Nmeros Complicados

Jaguaraci Batista Silva Instituto de Cincia e Tecnologia, Universidade Federal de So Paulo Campus So Jos dos Campos, So Paulo-SP jaguaracisilva@gmail.com

Resumo: O problema dos nmeros complicados definido por um subconjunto dos


nmeros de 1 a 1.000 que devem ser escritos usando expresses aritmticas. Ao final, devero ser exibidos os 10 nmeros mais complicados, onde o grau de complicao dado pela quantidade de vezes em que os nmeros so utilizados em uma expresso. O trabalho apresenta uma proposta de soluo baseada na tcnica de programao dinmica e tabelas de disperso.

Palavras-chaves: Complexidade, Algoritmo, Problema, Countdown.

1 - Introduo
O problema dos nmeros complicados definido por um subconjunto dos nmeros de 1 a 1.000 que devem ser escritos usando expresses aritmticas. Ao final, devero ser exibidos os 10 nmeros mais complicados, onde o grau de complicao dado pela quantidade de vezes em que os nmeros so utilizados em uma expresso. O estudo relacionou os conceitos envolvidos com o desafio, a partir do problema clssico de countdown [2], propondo um algoritmo iterativo para sua soluo utilizando a tcnica da programao dinmica [1] e tabelas de disperso [7]. O artigo apresenta, de forma breve, os conceitos relacionados com o problema clssico de countdown, suas definies e algumas solues encontradas na literatura na seo 2. Apresenta um maior detalhamento do problema e as solues propostas neste trabalho na seo 3. Em seguida so apresentados os resultados encontrados nas abordagens e uma breve anlise da complexidade dos algoritmos na seo 4. Por fim, a concluso e referncias utilizadas neste trabalho.

2 - O Problema Clssico de Countdown


O problema clssico de countdown surgiu em um programa popular da televiso britnica, que inclui um jogo de nmeros conhecido por countdown [2]. A essncia do problema (Figura1): dada uma sequncia de nmeros como entrada e um outro nmero como valor de sada, deve-se construir uma expresso aritmtica usando cada um dos nmeros da sequncia no mximo uma vez e o resultado da expresso deve ser o valor de sada [3].

Figura 1 Ilustrao do Problema Countdown. Diversos trabalhos podem ser encontrados na literatura sobre o desafio. Em [3], a partir de uma especificao formal, apresentado um programa simples que soluciona o problema, em seguida, outro mais eficiente, que aperfeioado atravs da explorao de propriedades aritmticas. Em [4] outro programa construdo atravs de uma definio formal e implementado com a tcnica da fora bruta atravs da programao funcional usando a linguagem Haskell. Outras abordagens utilizando programao funcional so apresentadas em [5] para soluo do mesmo problema. As solues propostas utilizaram alguns desses conceitos como referncia para resolver o desafio. A prxima seo melhora o entendimento do problema e destaca os principais entraves a serem vencidos, enquanto expe as solues propostas neste trabalho.

3 Soluo
A primeira parte do desafio escrever um subconjunto dos nmeros de 1 a 1.000 usando expresses aritmticas, as quais devem conter apenas os seguintes elementos: {5, 7, (, ) ,+ ,- ,*}. As expresses para os nmeros de 30 a 40 so ilustradas na Figura 2, importante notar que as expresses e nmero de parnteses devem ser to curtos quanto possvel. Outra informao importante o grau de complicao dos nmeros, que a quantidade de vezes que os nmeros (e.g. 5 e 7) aparecem. Tambm de acordo com a ilustrao (Figura 2), o grau de complicao do nmero 30 3, pois existem trs nmeros na expresso, por exemplo. Com base nessa ltima informao, deve-se listar os dez nmeros mais complicados entre 1 e 1.000, completando o desafio.

Figura 2 Exemplo de Nmeros entre 30 e 40.

O problema clssico de countdown assemelha-se a essncia da primeira parte do desafio, porm cada valor de sada da expresso um nmero natural e inteiro positivo com valor crescente. Assim, o estudo buscou um padro para montar as expresses e avali-las sem a necessidade de utilizao da tcnica da fora bruta. A soluo utilizou o conceito de tabelas de disperso [1][6][7] para localizao dos dados em 4 tabelas: tabela de representao de nmeros de 1 a 9, tabelas de mltiplos de 5 e 7 e a tabela principal. A primeira tabela consta a representao dos outros nmeros (Figura 3) que no so mltiplos de 5 e 7, porm sero utilizados na construo das expresses usando combinaes.

Figura 3 Tabela para outros Nmeros.

O acesso a tabela, contendo a representao dos outros nmeros, realizado quando do preenchimento das tabelas de mltiplos de 5 e 7. Para cada nmero (Figura 4 - N) existe uma expresso correspondente a ser encontrada atravs do clculo para localizao do registro na tabela de outros nmeros (O). A tabela de mltiplos calcula a diviso de cada nmero por 5 ou 7 (e.g. 10/5=2). Se o resultado corresponde a uma chave at o nmero 9, a expresso aritmtica ser localizada na tabela de outros nmeros na linha correspondente ao resultado do clculo (Figura 3).

Figura 4 Preenchimento da Tabela de Mltiplos.

O preenchimento da tabela segue para valores maiores at o limite proposto no desafio, neste caso, a prpria tabela de mltiplos tambm utilizada para localizao das expresses. Caso o valor de N seja divisvel por 5 ou 7 e maior que 9 (e.g.

N=50/5=10) a posio da linha ser o resultado dividido pelo nmero 5 ou 7 (e.g. 10/5=2). Caso o ndice no seja divisvel por esses nmeros haver uma subtrao com o ltimo mltiplo de j calculado (e.g. N=55/5=11). Neste caso, a expresso final a ser adicionada na tabela formada por duas expresses anteriores: a primeira a posio do ltimo mltiplo (e.g. 10/5=2) e a segunda ser localizada na tabela de outros nmeros (Figura 4) com o clculo da diferena restante (e.g. 11-10=1). De posse dessa anlise, foi construdo o algoritmo para realizar o preenchimento das tabelas de mltiplos de 5 e 7 utilizando a tcnica da programao dinmica [1], sendo exibido em detalhes na Listagem 1.

Figura 5 Tabela de Mltiplos.

As tabelas de mltiplos tero apenas as informaes de expresso aritmtica e grau de complicao de cada nmero mltiplo de 5 ou 7, onde cada nmero pode ter sua respectiva tabela ou apenas existir uma nica conforme a ilustrao da Figura 5. Os dados de cada expresso e grau de complicao de um nmero podem ser acessados diretamente atravs da linha (posio) e coluna (informao) das tabelas.
preencherTabela(int n, Tabela tabela, int configuracao) { int indice=0; int iMultiplo=0; indice=n/configuracao; Se (indice<10){ expressao=configuracao+"*("+outros[ndice].Expressao+")"; grauComplicacao = outros[ndice].GrauComplicacao+1; numeroComplicado = (expressao,grauComplicacao,n); tabela = numeroComplicado; } Seno{ Se (ehMultiplo(indice)){ configuracao=obterMultiplo(indice); //Retorna 5 ou 7 indice=indice/configuracao; Se(configuracao=7){ expressao =configuracao+"*("+multiplosSete[indice].Expressao+")"; grauComplicacao = multiplosSete[ndice].GrauComplicacao+1; }Seno{ expressao=configuracao+"*("+multiplosCinco[ndice].Expressao+")"; grauComplicacao=multiplosCinco[ndice].GrauComplicacao+1; } numeroComplicado = (expressao,grauComplicacao,n); tabela = numeroComplicado); valordoUltimoMultiplo[0]=n;

valordoUltimoMultiplo[1]=configuracao; } Seno{ iMultiplo=valordoUltimoMultiplo[0]/configuracao; indice=indice-iMultiplo; configuracao=obterMultiplo(n); Se(configuracao=5 ou configuracao=7){ expressao=tabela[iMultiplo].Expressao+"+"+configuracao; grauComplicacao=tabela[iMultiplo].GrauComplicacao+1; indice=configuracao; }Seno{ expressao=configuracao+"*("+tabela[iMultiplo].Expressao+")"; grauComplicacao=tabela[iMultiplo].GrauComplicacao+1; expressao=expressao+"+("+outros[indice].Expressao+")"; grauComplicacao=grauComplicacao+outros[ndice].GrauComplicacao+1; } numeroComplicado = (expressao,grauComplicacao,n); tabela=numeroComplicado); }}}

Listagem 1 Preenchimento da Tabela de Mltiplos.

O algoritmo (Listagem 1) inicia com as seguintes entradas: nmero a ser calculado, tabela a ser preenchida e a sua configurao (e.g. 5 ou 7). O ndice calculado para que se conhea a localizao da chave e dependendo do resultado, se menor ou maior que 10, a busca ser feita em uma tabela especfica. Caso o ndice possua um valor menor que 10, as informaes sero localizadas nas linhas da tabela de outros nmeros, caso seja maior e mltiplo de 5 ou 7 ser efetuado o clculo para conhecer qual a linha da tabela de mltiplos os dados podem ser encontrados. De acordo com a configurao da tabela, os dados a serem obtidos para anlise do nmero so formados pela expresso aritmtica que o representa e o seu grau de complicao. Se o ndice da busca calculado for um nmero mltiplo de 5 ou 7 o acesso aos dados ser feito diretamente em uma linha das respectivas tabelas de mltiplos. O valor do nmero e a informao sobre qual mltiplo ele se originou armazenada em um vetor. Essa informao til em uma condio a qual o ndice no seja um nmero mltiplo de 5 ou 7, onde sero realizados 2 acessos. O primeiro ser na tabela de mltiplos com a chave de acesso do ltimo nmero mltiplo de 5 ou 7 e o segundo ser na tabela de outros nmeros para obter o registro de acordo com o clculo j explicado (Seo 3). Assim, todo nmero com essa condio ter a sua expresso e grau de complicao formada por essas duas tabelas.

Figura 6 Tabela Soluo.

A tabela principal (Figura 6), onde so armazenados os nmeros para listagem dos 10 nmeros mais complicados, segue a mesma forma de clculo do preenchimento das tabelas de mltiplos, porm a nica diferena que so tratados todos os nmeros de 1 a 1.000. Quando um nmero menor que 10 os acessos so realizados na tabela de outros nmeros, do contrrio um clculo realizado para saber se o nmero mltiplo de 5 ou 7. Ainda feito mais um clculo para obter as informaes das linhas das tabelas de mltiplos e outros nmeros simultaneamente, da mesma forma explicada anteriormente (Listagem 1). De posse dessa anlise foi construdo o algoritmo final da soluo apresentado na Listagem 2.
Se (preencherTabelaOutros()>0){ int indice=0; int indiceMultiplo=0; int numeroMultiplo; Para i de 1 at 1000 incremente i+1 Faa{ Se(i<10){ expressao=outros[i].Expressao; grauComplicacao=outros[i].GrauComplicacao; valor=outros[i].Valor; numeroComplicado=(expressao,grauComplicacao,valor); Se(i=5){ multiplosCinco=numeroComplicado; }Seno Se(i=7){ multiplosSete=numeroComplicado); } principal=numeroComplicado; }Seno{

Se(ehMultiplo(i)){ numeroMultiplo=obterMultiplo(i); indice=i/numeroMultiplo; Se(numeroMultiplo=12){ //Multiplo de 5 e 7 preencherTabela(i,multiplosSete,7); preencherTabela(i,multiplosCinco,5); numeroMultiplo=7; indice=i/numeroMultiplo; }Seno Se(numeroMultiplo=7){ preencherTabela(i,multiplosSete,7); expressao=multiplosSete[indice].Expressao; grauComplicacao=multiplosSete[indice].GrauComplicacao; numeroComplicado=(expressao,grauComplicacao,i); }Seno Se(numeroMultiplo=5){ preencherTabela(i,multiplosCinco,5); expressao=multiplosCinco[indice].Expressao; grauComplicacao=multiplosCinco[ndice].GrauComplicacao; numeroComplicado=(expressao,grauComplicacao,i); } principal=numeroComplicado; valordoUltimoMultiplo[0]=i; valordoUltimoMultiplo[1]=numeroMultiplo; }Seno{ iMultiplo=valordoUltimoMultiplo[0]/valordoUltimoMultiplo[1]; indice=i-valordoUltimoMultiplo[0]; Se(valordoUltimoMultiplo[1]=7){ expressao=multiplosSete[iMultiplo].Expressao; grauComplicacao=multiplosSete[iMultiplo].GrauComplicacao; }Seno{ expressao=multiplosCinco[iMultiplo].Expressao; grauComplicacao=multiplosCinco[iMultiplo].GrauComplicacao; } expressao=expressao+"+("+outros[ndice].Expressao+")"; grauComplicacao=grauComplicacao+outros[ndice].GrauComplicacao; numeroComplicado=(expressao,grauComplicacao,i); principal = numeroComplicado; }}}

Listagem 2 Algoritmo Proposto para Soluo.

Alm dos clculos efetuados para obteno das chaves de acesso nas tabelas, o algoritmo tambm, ao tempo em que realiza as verificaes, preenche as tabelas de mltiplos iterativamente. Por isso, este estudo pode comprovar que utilizando uma estrutura de dados em forma de tabelas de disperso [1][6][7] a complexidade O(1). No entanto, por conta da iterao necessria para realizar a anlise do grau de complicao de todos os nmeros, a complexidade total do algoritmo O(n).

4 - Resultados
O estudo utilizou um notebook de 32 bits, com processador Intel Core2 Duo (1.83 GHz) e memria de 3GB (667 MHz DDR2), sistema operacional Microsoft Windows Vista Business (Verso 6.0, Compilao 6002, Service Pack 2) o ambiente de desenvolvimento Eclipse 3.5.1 (Build 20090920-1017), com o Java Development Kit (JDK) 1.6 e linguagem de programao Java.

Figura 7 Os 10 Nmeros mais Complicados.

Conforme a descrio da segunda parte do desafio (Seo 3), a Figura 7 exibe os 10 nmeros mais complexos aps a execuo do algoritmo proposto neste estudo. Todos os nmeros foram obtidos to rapidamente, que no foi possvel conhecer o seu tempo em milissegundos e o critrio de desempate, quando do mesmo grau de complicao, foi escolher o que tinha mais parnteses para aparecer no ranking. Tambm o algoritmo de ordenao Timsort[8], utilizado neste estudo, possui complexidade O(n), igual complexidade das iteraes para todos os nmeros propostos no desafio e o tempo total da soluo foi apenas 0,016ms. Para averiguar o desempenho do algoritmo, outra simulao foi realizada para valores enormes, onde o algoritmo conseguiu listar os 10 nmeros mais complicados entre 1 e 1 milho em apenas 3 segundos.

5 - Concluso
O problema dos nmeros complicados definido por um subconjunto dos nmeros de 1 a 1.000 que devem ser escritos usando expresses aritmticas. Ao final, devero ser exibidos os 10 nmeros mais complicados, onde o grau de complicao dado pela quantidade de vezes em que os nmeros so utilizados em uma expresso. Este trabalho associou o desafio ao problema clssico de countdown e apresentou uma soluo baseada na tcnica da programao dinmica utilizando tabelas de disperso. O estudo buscou um padro para montar as expresses e avali-las sem a necessidade de utilizao de um gerador e avaliador de expresses aritmticas. Foi criado um algoritmo que utiliza tabelas de disperso. Por haver uma quantidade de dados pequena e necessidade de armazenar e manipular resultados de forma iterativa, a tcnica da programao dinmica foi empregada para efetuar os clculos e preencher as tabelas. A soluo comprovou que a utilizao de tabelas de disperso como estrutura de dados, atravs de listas ligadas, possui complexidade O(1) e por conta do desafio requerer uma iterao entre 1 e 1.000 o algoritmo proposto para soluo do problema possui complexidade total O(n), mesmo com a utilizao de um algoritmo de ordenao. Tambm demonstrou a sua eficincia para resolver o desafio com grandes

volumes de dados, em uma simulao, resolveu o desafio para valores entre 1 e 1 milho em apenas 3 segundos. Comparando os resultados com outros estudos, que propuseram solues para o problema de countdown [2][3], o algoritmo construdo neste estudo pode ser ainda mais eficiente. A utilizao de uma abordagem com a tcnica de programao dinmica e tabelas de disperso, em oposio s solues encontradas na literatura, pode resolver o problema de countdown com grande desempenho e complexidade O(n).

Referncias
[1] Cormen, T.H., Leiserson, C.E., Rivest, R.L., Stein, C.. "Introduction to Algorithms", MIT Press, Cambridge, Massachusetts, London, 2nd Ed, 2001. [2] Hinze, Ralf.. Countdown Problem. Institut fr Informatik III, Universitt Bonn. Rmerstrae 164, 53117 Bonn, Germany, 2002. [3] Hutton, Graham..Functional Pearl The countdown problem. University of Nottingham, School of Computer Science and IT. Cambridge University Press, United Kingdom, 2002. [4] Programming in Haskell, The countdown Problem. www.cs.nott.ac.uk/~gmh/chapter11.ppt, acessado em 11 de Junho de 2012. [5] Bird, R. Pearls of Functional Algorithm Design. Cap. 20 The Countdown Problem. Cambridge University Press, ISBN 978-0521-5133-88. New York, 2010. [6] Silva, A. P. C.. Hashing (Tabela de Disperso). www.joinville.udesc.br. Acessado em 15 de junho de 2012. [7] Celes, W., Rangel, J.L.. Tabelas de Disperso. Material de Apoio ao Ensino. http://www.ic.unicamp.br/~ra069320/PED/MC102/1s2008/Apostilas/Cap17.pdf. Acessado em 15 de junho de 2012. [8] Wikipedia. TimSort. http://en.wikipedia.org/wiki/Timsort. Acessado em 15 de junho de 2012.

You might also like