Você está na página 1de 10

Captulo 0

Prlogo
Olhe ao seu redor. Computadores e redes esto em todo lugar, possibilitando uma intrincada teia de complexas atividades humanas: educao, comrcio, diverso, pesquisa, manufatura, gerenciamento de sade, comunicao humana, at mesmo guerra. Dos dois principais pilares tecnolgicos dessa proliferao incrvel, um bvio: o impressionante passo com o qual os avanos em microeletrnica e projeto de circuitos integrados tm nos trazido hardware cada vez mais rpido. Este livro conta a histria do outro empreendimento intelectual que crucialmente abastece a revoluo da computao: algoritmos ecientes. uma histria fascinante. Aproximem-se e ouam com ateno.

0.1 Livros e algoritmos


Duas idias mudaram o mundo. Em 1448, na cidade alem de Mainz, um ourives chamado Johann Gutenberg descobriu uma maneira de imprimir livros juntando peas metlicas mveis. A alfabetizao se espalhou, a Idade Mdia terminou, o intelecto humano foi liberado, cincia e tecnologia triunfaram, a Revoluo Industrial aconteceu. Muitos historiadores dizem que devemos tudo isso tipograa. Imagine um mundo no qual somente uma elite pudesse ler essas linhas! Mas outros insistem em que o desenvolvimento-chave no foi a tipograa, mas os algoritmos.

Johann Gutenberg 13981468

Corbis
1

0.2 Fibonacci entra em cena

Hoje estamos to acostumados a escrever nmeros em decimal, que fcil esquecer que Gutenberg escreveria o nmero 1448 como MCDXLVIII. Como voc soma dois numerais romanos? O que MCDXLVIII + DCCCXII? (E apenas tente pensar em multiplic-los.) Mesmo um homem inteligente como Gutenberg provavelmente sabia apenas somar e subtrair pequenos nmeros usando seus dedos; para qualquer coisa mais complicada ele tinha de consultar um especialista em baco. O sistema decimal, inventado na ndia por volta de 600 d.C., foi uma revoluo no raciocnio quantitativo: usando apenas dez smbolos, mesmo nmeros muito grandes podiam ser escritos de maneira compacta, e aritmtica podia ser feita ecientemente sobre eles seguindo passos elementares. Entretanto, essas idias levaram um longo tempo para serem difundidas, impedidas por barreiras tradicionais de linguagem, distncia e ignorncia. O meio mais inuente de transmisso acabou sendo um livro-texto, escrito em rabe no sculo IX por um homem que vivia em Bagd. Al Khwarizmi estabeleceu os mtodos bsicos para adicionar, multiplicar e dividir nmeros at mesmo extrair a raiz quadrada e calcular os dgitos de . Esses procedimentos eram precisos, no ambguos, mecnicos, ecientes, corretos em suma, eram algoritmos, um termo cunhado para homenagear o sbio homem, depois que o sistema decimal foi nalmente adotado na Europa, aps muitos sculos. Desde ento, o sistema decimal posicional e seus algoritmos numricos desempenharam um papel enorme na civilizao ocidental. Eles possibilitaram a cincia e a tecnologia; aceleraram a indstria e o comrcio. E quando, muito depois, o computador foi projetado, ele incorporou explicitamente o sistema posicional nos seus bits, palavras e unidade aritmtica. Em todo lugar, cientistas se ocuparam em desenvolver algoritmos mais e mais complexos para todo tipo de problemas e inventar novas aplicaes por m, mudando o mundo.

0.2 Fibonacci entra em cena


O trabalho de Al Khwarizmi no poderia ter chegado ao Ocidente no fosse pelos esforos de um homem: o matemtico italiano do sculo XV Leonardo Fibonacci, que enxergou o potencial do sistema posicional e trabalhou duro para desenvolv-lo mais e divulg-lo. Hoje Fibonacci mais amplamente conhecido por sua famosa seqncia de nmeros
0,1,1,2,3,5,8,13,21,34, ...,

cada um a soma dos dois antecessores imediatos. Mais formalmente, os nmeros de Fibonacci Fn so gerados pela regra simples
Fn 5 c Fn 2 1 1 Fn 2 2 1 0 se n . 1 se n 5 1 se n 5 0.

Captulo 0

Algoritmos

Nenhuma outra seqncia de nmeros foi estudada to extensivamente, ou aplicada a mais reas: biologia, demograa, arte, arquitetura, msica, para citar apenas algumas. E, com as potncias de 2, ela a seqncia favorita da cincia da computao. De fato, os nmeros de Fibonacci crescem quase to rapidamente quanto as potncias de 2: por exemplo, F30 mais que um milho e F100 j tem 21 dgitos de comprimento! Em geral, Fn < 20,694n (veja o Exerccio 0.3). Mas qual o valor preciso de F100 ou de F200? O prprio Fibonacci certamente gostaria de saber tais coisas. Para respondermos, precisamos de um algoritmo para computar o n-simo nmero de Fibonacci.

Leonardo de Pisa (Fibonacci) 1170-1250

Corbis
Um algoritmo exponencial
Uma idia implementar cegamente a denio recursiva de Fn. Aqui est o algoritmo resultante, na notao de pseudocdigo usada em todo este livro: funo fib1(n) se n 0 : retorna 0 se n 1 : retorna 1 retorna fib1(n 1) fib1(n 2) Quando temos um algoritmo, existem trs perguntas que sempre fazemos sobre ele: 1. Ele correto? 2. Quanto tempo ele toma, em funo de n? 3. E, ser que podemos fazer melhor? A primeira questo no vale a pena considerar aqui, pois esse algoritmo precisamente a denio de Fibonacci para Fn. Mas a segunda requer uma resposta. Seja T(n) o nmero de passos de computao necessrios para computar fib1(n), o que podemos dizer sobre essa funo? Para os valores iniciais, se n menor que 2, o procedimento pra quase imediatamente, aps apenas um par de passos. Portanto,
T(n) 2 para n 1.

0.2 Fibonacci entra em cena

Para valores maiores de n, h duas chamadas recursivas de fib1, tomando tempo T(n 1) e T(n 2), respectivamente, mais trs passos de computao (checagem do valor de n e a adio nal). Portanto,
T(n) T(n 1) T(n 2) 3 para n 1.

Compare isso relao de recorrncia de Fn: vemos imediatamente que T(n) Fn. Isto notcia muito ruim: o tempo de execuo do algoritmo cresce to rapidamente quanto os prprios nmeros de Fibonacci! T(n) exponencial em n, o que implica que o algoritmo impraticavelmente lento, exceto para valores muito pequenos de n. Sejamos um pouco mais concretos sobre quo ruim o tempo exponencial. Para computar F200, o algoritmo fib1 executa T 1 200 2 $ F200 $ 2138 passos elementares de computao. Quanto tempo na verdade isso toma depende, claro, do computador usado. Hoje, o computador mais rpido do mundo o NEC Earth Simulator, que executa 40 trilhes de passos por segundo. Mesmo nessa mquina, fib1(200) tomaria pelo menos 292 segundos. Isso signica que, se comearmos a execuo agora, ela ainda estaria rodando muito depois de o Sol se transformar numa estrela gigante vermelha. Mas a tecnologia est melhorando rapidamente a velocidade dos computadores tem dobrado mais ou menos a cada 18 meses, um fenmeno s vezes chamado de lei de Moore. Com esse crescimento extraordinrio, talvez fib1 rode muito mais rpido nas mquinas do prximo ano. Vejamos o tempo de execuo de fib1(n) proporcional a 20,694n (1,6)n, portanto computar Fn1 toma 1,6 vez mais tempo do que Fn. E, segundo a lei de Moore, os computadores cam mais ou menos 1,6 vez mais rpidos a cada ano. Portanto, se pudermos computar F100 em tempo razovel na tecnologia deste ano, no prximo ano conseguiremos computar F101. E no ano seguinte, F102. E assim por diante: apenas mais um nmero de Fibonacci a cada ano! Tal a praga do tempo exponencial. Em suma, nosso algoritmo recursivo ingnuo correto, mas irremediavelmente ineciente. Ser que podemos fazer melhor?

Um algoritmo polinomial
Tentemos entender por que fib1 to lento. A Figura 0.1 mostra a cascata de chamadas recursivas disparada por uma nica chamada a fib1(n). Note que muitas computaes so repetidas! Um esquema mais sensato salvaria os resultados intermedirios os valores F0, F1, ..., Fn1 to logo eles se tornem conhecidos. funo fib2(n) se n 0: retorna 0 crie um vetor f[0...n] f[0] 0, f[1] 1 para i 2...n: f[i] = f[i 1] f[i 2] retorna f[n]

Captulo 0

Algoritmos

Figura 0.1

A proliferao de chamadas recursivas em fib1.

Fn

Fn1

Fn2

Fn2

Fn3

Fn3

Fn4

Fn3

Fn4 Fn4 Fn5

Fn4 Fn5

Fn5 Fn6

Como no caso de fib1, a correo desse algoritmo auto-evidente porque ele usa diretamente a denio de Fn. Quanto tempo ele toma? O loop interno consiste em um nico passo de computao executado n 1 vezes. Portanto, o nmero de passos usados por fib2 linear em n. De exponencial, baixamos para polinomial, um enorme avano em tempo de execuo. Agora perfeitamente razovel computar F200 ou mesmo F200.0001. Como veremos em todo o livro, o algoritmo certo faz toda a diferena.

Uma anlise mais cuidadosa


Nesta discusso at agora, temos contado o nmero de passos bsicos de computao executados por algoritmo e pensado neles como se tomassem uma quantidade constante de tempo. Isso uma simplicao muito til. Alm disso, o conjunto de instrues do processador tem uma variedade de primitivas bsicas desvio, armazenamento na memria, comparao de nmeros, aritmtica simples e assim por diante e, em vez de distinguir entre essas operaes elementares, muito mais conveniente junt-las em uma nica categoria. Mas ao revermos nosso tratamento para os algoritmos de Fibonacci, fomos liberais demais com o que consideramos um passo bsico. razovel tratar adio como um nico passo de computao se nmeros pequenos esto sendo adicionados, digamos, nmeros de 32 bits. Mas o n-simo nmero de Fibonacci tem comprimento de cerca de

Para melhor avaliar a importncia dessa dicotomia entre algoritmos exponenciais e polinomiais, o leitor pode se adiantar e ler a histria de Sissa e Moore, no Captulo 8.

6 0,694n, e isso pode exceder bastante 32, quando n cresce. Operaes aritmticas em nmeros arbitrariamente grandes no podem ser realizadas em um passo nico, de tempo constante. Precisamos vericar nossas estimativas anteriores de tempo de execuo e torn-las mais honestas. Veremos no Captulo 1 que a adio de dois nmeros de n-bits toma tempo proporcional mais ou menos a n; isso no muito difcil de entender se voc pensa no procedimento para adio da escola, que opera um dgito a cada vez. Portanto fib1, que realiza cerca de Fn adies, na verdade usa um nmero de passos bsicos proporcional mais ou menos a nFn. Da mesma maneira, o nmero de passos tomados por fib2 proporcional a n2, ainda polinomial em n e, portanto, exponencialmente superior a fib1. Essa correo na anlise de tempo de execuo no diminui nosso avano. Mas, ser que podemos fazer melhor do que fib2? De fato podemos: veja o Exerccio 0.4.

0.3 A notao O

0.3 A notao O
Acabamos de ver como a negligncia na anlise de tempos de execuo pode levar a um nvel inaceitvel de impreciso no resultado. Mas o perigo oposto tambm est presente: possvel ser preciso demais. Uma anlise perspicaz sempre baseada nas simplicaes certas. Expressar o tempo de execuo em termos de passos bsicos de computao j uma simplicao. Inclusive, o tempo gasto por um tal passo depende crucialmente do processador em questo e mesmo de detalhes, tais como a estratgia de cache (que resulta em tempos sutilmente diferentes de uma execuo para prxima). Levar em conta as mincias da arquitetura um pesadelo, uma tarefa to complexa que leva a um resultado no-generalista de um computador para outro. Faz mais sentido, portanto, buscar uma caracterizao simples, independente da mquina, para a ecincia de um algoritmo. Para esse m, sempre expressaremos o tempo de execuo contando o nmero de passos bsicos de computao como uma funo do tamanho da entrada. Essa simplicao leva a uma outra. Em vez de reportar que um algoritmo toma, digamos, 5n3+4n+3 passos em uma entrada de tamanho n, muito mais fcil deixar de fora termos de menor ordem, tais como 4n e 3 (que se tornam insignicantes medida que n cresce), e mesmo o detalhe do coeciente 5 do termo de maior ordem (os computadores sero 5 vezes mais rpidos de qualquer forma em poucos anos), e apenas dizer que o algoritmo toma tempo O(n3) (pronunciado ozo de n3). chegada a hora de denir essa notao precisamente. Assim, pense em f(n) e g(n) como os tempos de execuo de dois algoritmos sobre entradas de tamanho n. Sejam f(n) e g(n) duas funes de inteiros positivos em reais positivos. Dizemos que f = O(g) (que signica que f no cresce mais rpido do que g) se existe uma constante c 0 tal que f(n) c g(n). Dizer f O(g) est em leve analogia a dizer f g. Difere da noo usual de por causa da constante c, de forma que, por exemplo, 10n O(n). Tal constante tambm nos permite desconsiderar o que acontece para pequenos valores de n. Por exemplo,

Captulo 0

Algoritmos

suponha que estejamos escolhendo entre dois algoritmos para determinada tarefa computacional. Um toma f1(n)=n2 passos, enquanto o outro toma f2(n) 2n 20 passos (Figura 0.2). Qual melhor? Bem, isso depende do valor de n. Para n 5, n2 menor; depois disso, 2n 20 claramente o vencedor. Nesse caso, f2 escala muito melhor medida que n cresce e, portanto, superior. Essa superioridade capturada pela notao O: f2 O(f1), porque
f2 1 n 2 2n 1 20 5 # 22 f1 1 n 2 n2

para todo n; por outro lado, f1 O(f2), pois a razo f1 1 n 2 f2 1 n 2 5 n 2 1 2n 1 20 2 pode tornar-se arbitrariamente grande e, portanto, nenhuma constante c far a denio funcionar.

Figura 0.2

Qual tempo de execuo melhor?


100

90

80

70

60

n2
50 40

30

2n+20

20

10

10

Agora outro algoritmo aparece, um que usa f3(n) n 1 passos. Isso melhor do que f2? Certamente, mas apenas por um fator constante. A discrepncia entre 2n 20 e n 1 mnima comparada ao enorme vo entre n2 e 2n 20. Para concentrarmonos na viso geral, tratamos funes como equivalentes se elas diferem apenas por constantes multiplicativas. Retornando denio de O, vemos que f2 5 O 1 f3 2 :
f2 1 n 2 2n 1 20 # 20, 5 n11 f3 1 n 2

e, claro, f3 O(f2), desta vez com c 1.

8 Assim como O 1 # 2 anlogo a , podemos denir anlogos de e como se segue: f 5 Q 1 g 2 signica f 5 O 1 g 2 e f 5 V 1 g 2 . No exemplo anterior, f2 5 Q 1 f3 2 e f1 5 V 1 f3 2 . A notao O nos permite ter uma idia do todo. Quando confrontados com uma funo complicada como 3n2 1 4n 1 5, simplesmente a substitumos por O 1 f 1 n 2 2 , onde f 1 n 2 to simples quanto possvel. Neste exemplo particular, usamos O 1 n2 2 , porque a poro quadrtica da soma domina o restante. Aqui esto algumas regras criteriosas que, omitindo termos dominados, ajudam a simplicar funes: 1. Constantes multiplicativas podem ser omitidas: 14n2 se torna n2. 2. na domina nb se a b: por exemplo, n2 domina n. 3. Qualquer exponencial domina qualquer polinomial: 3n domina n5 (domina at mesmo 2n). 4. Da mesma maneira, qualquer polinomial domina qualquer logaritmo: n domina (log n)3. Isso tambm signica, por exemplo, que n2 domina n log n. No interprete mal esse cavalheirismo com constantes. Programadores e projetistas de algoritmos esto muito interessados em constantes e virariam noites para fazer um algoritmo rodar duas vezes mais rpido. Mas entender algoritmos no nvel deste livro seria impossvel sem a simplicidade fornecida pela notao O. f 5 V 1 g 2 signica g 5 O 1 f 2

Exerccios

Exerccios

0.1. Em cada uma das seguintes situaes, indique se f 5 O 1 g 2 , ou f 5 V 1 g 2 ou ambos (caso em que f 5 Q 1 g 2 ). f(n) g(n)

(a) n 100 n 200 1/2 (b) n n2/3 (c) 100n log n n (log n)2
(d) n log n (e) log 2n (f) 10 log n (g) n1,01 (h) n /log n (i) (j) n0,1 (log n)log n
2

10n log 10n log 3n log (n2) n log2 n n(log n)2 (log n)10 n/log n (log n)3 5log2 n 3n

(l) n1/2 (m) n2n

(k) "n

Captulo 0

Algoritmos

(n) 2n (o) n! (p) (log n)log n (q) a n ik i51 0.2.

2n1 2n 2 2(log2 n) nk1

Mostre que, se c um nmero real positivo, ento g(n) 1 c c2 ... cn :

Moral da histria: em termos de , a soma de uma srie geomtrica simplesmente o primeiro termo se a srie estritamente decrescente, o ltimo termo se a srie estritamente crescente, ou o nmero de termos se a srie invarivel. 0.3. O nmeros de Fibonacci F0, F1, F2, ..., so denidos pela regra F0 5 0, F1 5 1, Fn 5 Fn 2 1 1 Fn 2 2. Neste problema vamos conrmar que a seqncia cresce exponencialmente e obter algumas cotas sobre o seu crescimento.

(a) Q 1 1 2 se c 1. (b) Q 1 n 2 se c 1. (c) Q 1 cn 2 se c 1.

(a) Use induo para provar que Fn $ 20,5n para n 6. (b) Encontre uma constante c 1 tal que Fn # 2cn para todo n 0. Mostre que sua resposta est correta. (c) Qual a maior constante c que voc pode encontrar para a qual Fn 5 V 1 2cn 2 ?
0.4. Existe uma maneira mais rpida de computar o n-simo nmero de Fibonacci do que com fib2 (pgina 4)? Uma idia envolve matrizes. Comeamos por escrever as equaes F1 5 F1 e F2 5 F0 1 F1 em notao de matriz: De modo similar, e, em geral Fn Fn 1 1 5 0 1 1 n # F0 . 1 F1 F2 0 5 F3 1 1 # F1 0 5 F2 1 1 1 2 # F0 F1 1 F1 0 5 F2 1 1 # F0 . 1 F1

Ento, para computar Fn, suciente elevar a matriz 2 2, X, a n-sima potncia. (a) Mostre que duas matrizes 2 2 podem ser multiplicadas usando 4 adies e 8 multiplicaes.

10
Mas quantas multiplicaes de matrizes so necessrias para computar Xn? (b) Mostre que O(log n) multiplicaes de matrizes so sucientes para computar Xn. (Dica: pense na computao de X8.) Portanto o nmero de operaes aritmticas realizadas por nosso algoritmo baseado em matrizes, chamemos de fib3, apenas O(log n), em comparao a O(n) para fib2. Quebramos outra barreira exponencial? O problema que nosso novo algoritmo envolve multiplicao, no apenas adio; e multiplicaes de nmeros grandes so mais lentas que adies. J vimos que, quando a complexidade das operaes aritmticas levada em conta, o tempo de execuo de fib2 torna-se O(n2). (c) Mostre que todos os resultados intermedirios de fib3 possuem O(n) bits de comprimento. (d) Seja M(n) o tempo de execuo de um algoritmo para multiplicar nmeros de n bits e assuma que M(n) O(n2) (o mtodo da escola para multiplicao, recordado no Captulo 1, alcana isto). Prove que o tempo de execuo de fib3 O(M(n) log n). (e) Voc pode provar que o tempo de execuo de fib3 O(M(n))? Assuma M(n) (na) para algum 1 a 2.(Dica: O tamanho dos nmeros multiplicados dobra com cada elevao ao quadrado.) Concluindo, para que fib3 seja mais rpido do que fib2 depende de podermos multiplicar inteiros de n bits mais rpido que O(n2). Voc acha que isso possvel? (A resposta est no Captulo 2.) Por m, existe uma frmula para os nmeros de Fibonacci: Fn 5 "5 1 1 1 "5 1 1 2 "5 2 . 2 2 "5
n n

Exerccios

Assim, pareceria que precisamos apenas elevar um par de nmeros n-sima potncia para computar Fn. O problema que esses nmeros so irracionais, e comput-los com preciso suciente no trivial. De fato, nosso mtodo de matrizes, fib3, pode ser visto como uma maneira indireta de elevar esses nmeros irracionais n-sima potncia. Se voc se lembra da lgebra linear, deve entender o porqu. (Dica: Quais so os autovalores da matriz X?)

Você também pode gostar