You are on page 1of 81

See

discussions, stats, and author profiles for this publication at: https://www.researchgate.net/publication/267785292

Anlise de Algoritmos
Chapter July 2009

CITATIONS

READS

71

1 author:
Paulo Feofiloff
University of So Paulo
13 PUBLICATIONS 52 CITATIONS
SEE PROFILE

All content following this page was uploaded by Paulo Feofiloff on 25 November 2014.
The user has requested enhancement of the downloaded file. All in-text references underlined in blue
are linked to publications on ResearchGate, letting you access and read them immediately.

Minicurso de
Anlise de Algoritmos
http://www.ime.usp.br/~pf/livrinho-AA/

Paulo Feofiloff
Departamento de Cincia da Computao
Instituto de Matemtica e Estatstica
Universidade de So Paulo
2 de janeiro de 2013

FEOFILOFF

Sumrio
1

Introduo

1.1

Problemas e instncias . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.2

Consumo de tempo de algoritmos . . . . . . . . . . . . . . . . . . . . 10

1.3

Recurso e algoritmos recursivos . . . . . . . . . . . . . . . . . . . . . 11

1.4

Convenes de notao . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

Comparao assinttica de funes

13

2.1

Notao O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2.2

Notao mega . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

2.3

Notao Teta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

2.4

Consumo de tempo de algoritmos . . . . . . . . . . . . . . . . . . . . 15

Soluo de recorrncias

17

3.1

Exemplo 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

3.2

Exemplo 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

3.3

Exemplo 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

3.4

Exemplo 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

3.5

Teorema mestre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

Ordenao de vetor

25

4.1

Algoritmo Mergesort . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

4.2

Diviso e conquista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

Segmento de soma mxima

27

5.1

O problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

5.2

Primeiro algoritmo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

5.3

Segundo algoritmo: diviso e conquista . . . . . . . . . . . . . . . . . 29

5.4

Terceiro algoritmo: programao dinmica . . . . . . . . . . . . . . . 30

5.5

Observaes sobre programao dinmica . . . . . . . . . . . . . . . . 32

FEOFILOFF

O problema da maioria

33

6.1

O problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

6.2

Um algoritmo linear . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

Multiplicao de nmeros naturais

37

7.1

O problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

7.2

O algoritmo usual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

7.3

Diviso e conquista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

7.4

Algoritmo de Karatsuba . . . . . . . . . . . . . . . . . . . . . . . . . . 40

7.5

Detalhes de implementao . . . . . . . . . . . . . . . . . . . . . . . . 41

7.6

Diviso e conquista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

Escalonamento de intervalos

43

8.1

O problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

8.2

A estrutura recursiva do problema . . . . . . . . . . . . . . . . . . . . 44

8.3

Algoritmo de programao dinmica . . . . . . . . . . . . . . . . . . . 44

As linhas de um pargrafo

47

9.1

O problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

9.2

A estrutura recursiva do problema . . . . . . . . . . . . . . . . . . . . 48

9.3

Um algoritmo de programao dinmica . . . . . . . . . . . . . . . . 49

10 Mochila de valor mximo

51

10.1 O problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
10.2 A estrutura recursiva do problema . . . . . . . . . . . . . . . . . . . . 51
10.3 Algoritmo de programao dinmica . . . . . . . . . . . . . . . . . . . 52
10.4 Instncias especiais do problema da mochila . . . . . . . . . . . . . . 54
11 Mochila de valor quase mximo

55

11.1 O problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
11.2 Algoritmo de aproximao . . . . . . . . . . . . . . . . . . . . . . . . . 55
11.3 Observaes sobre algoritmos de aproximao . . . . . . . . . . . . . 57
12 A cobertura de um grafo

59

12.1 Grafos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
12.2 O problema da cobertura . . . . . . . . . . . . . . . . . . . . . . . . . . 59
12.3 Um algoritmo de aproximao . . . . . . . . . . . . . . . . . . . . . . 60
12.4 Comentrios sobre o mtodo primal-dual . . . . . . . . . . . . . . . . 62
12.5 Instncias especiais do problema . . . . . . . . . . . . . . . . . . . . . 62

ANLISE DE ALGORITMOS

13 Conjuntos independentes em grafos

63

13.1 O problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
13.2 Algoritmo probabilstico . . . . . . . . . . . . . . . . . . . . . . . . . . 64
13.3 Comentrios sobre algoritmos probabilsticos . . . . . . . . . . . . . . 66
14 Busca em largura num grafo

67

14.1 O problema do componente . . . . . . . . . . . . . . . . . . . . . . . . 67


14.2 Busca em largura: verso preliminar . . . . . . . . . . . . . . . . . . . 67
14.3 Busca em largura: verso mais concreta . . . . . . . . . . . . . . . . . 69
15 Busca em profundidade num grafo

71

15.1 Busca em profundidade . . . . . . . . . . . . . . . . . . . . . . . . . . 71


Posfcio

74

Bibliografia

77

ndice remissivo

79

FEOFILOFF

Prefcio
A Anlise de Algoritmos (veja o verbete Analysis of Algorithms na Wikipedia) uma
disciplina bem-estabelecida, coberta por um bom nmero de excelentes livros (a maioria em ingls). Este livrinho faz uma modesta introduo ao assunto. Depois de tratar
brevemente de alguns pr-requisitos (como notao assinttica e resoluo de recorrncias), o texto analisa alguns algoritmos clssicos, discute sua eficincia, e chama a ateno para as estratgias (diviso e conquista, programao dinmica, mtodo primaldual) que levaram sua concepo.
Este livrinho uma verso corrigida do minicurso que ministrei nas JAI (Jornadas
de Atualizao em Informtica) de 2009 da SBC (Sociedade Brasileira de Computao),
ocorridas em Bento Gonalves, RS, em julho de 2009. O minicurso foi publicado no
livro organizado por Andr P. L. F. de Carvalho e Tomasz Kowaltowski [5].
O texto deve muito a Cristina Gomes Fernandes e Jos Coelho de Pina Jr., ambos
do Departamento de Cincia da Computao do Instituto de Matemtica e Estatstica
da USP, que contriburam com material, ideias e valiosas sugestes.

IMEUSP, So Paulo, agosto de 2009


P. F.

FEOFILOFF

Captulo 1

Introduo
A Anlise de Algoritmos1 estuda certos problemas computacionais recorrentes, ou seja,
problemas que aparecem, sob diversos disfarces, em uma grande variedade de aplicaes e de contextos. A anlise de um algoritmo para um dado problema trata de
1. provar que o algoritmo est correto e
2. estimar o tempo que a execuo do algoritmo consome.
(A estimativa do espao de memria usado pelo algoritmo tambm importante em
muitos casos.) Dados dois algoritmos para um mesmo problema, a anlise permite
decidir qual dos dois mais eficiente.
Pode-se dizer que a Anlise de Algoritmos uma disciplina de engenharia, pois
ela procura prever o comportamento de um algoritmo antes que ele seja efetivamente
implementado e colocado em produo.
Num nvel mais abstrato, a anlise de algoritmos procura identificar aspectos estruturais comuns a algoritmos diferentes e estudar paradigmas de projeto de algoritmos
(como a diviso e conquista, a programao dinmica, o mtodo primal-dual, etc.)
Este texto uma breve introduo Anlise de Algoritmos, baseada nos excelentes
livros de Cormen, Leiserson, Rivest e Stein [3], de Brassard e Bratley [2], de Bentley [1],
de Kleinberg e Tardos [10] e de Manber [14].
No restante desta introduo, faremos uma rpida reviso de conceitos bsicos e
fixaremos a notao e a terminologia empregadas no texto.

1.1

Problemas e instncias

Da mesma forma que distinguimos um algoritmo de sua aplicao a uma particular


entrada, convm distinguir problemas de suas instncias. Todo problema computacional uma coleo de instncias.2 Cada instncia do problema definida por um
particular conjunto de dados.
1

A expresso foi cunhada por D. E. Knuth [12].


A palavra instncia um neologismo importado do ingls. Ela est sendo empregada aqui no sentido
de exemplo, espcime, amostra, ilustrao.
2

10

FEOFILOFF

Considere, por exemplo, o problema de encontrar a mdia dos elementos de um


vetor A[1 . . n] de nmeros. Uma das instncias deste problema consiste em encontrar
a mdia dos elementos do vetor (876, 145, 323, 112, 221).
Em discusses informais, aceitvel dizer problema quando instncia do problema seria mais correto. Em geral, entretanto, importante manter clara a distino
entre os dois conceitos.
O tamanho de uma instncia de um problema a quantidade de dados necessria
para descrever a instncia. O tamanho de uma instncia descrito, em geral, por um
s nmero natural, mas s vezes conveniente usar dois ou at mais nmeros. A ideia
de tamanho permite dizer que uma instncia menor ou maior que outra.
No problema da mdia citado acima, por exemplo, razovel dizer que o tamanho
da instncia (876, 145, 323, 112, 221) 5 e, em geral, que o tamanho de uma instncia A[1 . . n] n. (Dependendo das circunstncias, entretanto, pode ser mais apropriado adotar o nmero total de dgitos decimais de A[1 . . n] como tamanho da instncia.
Nesse caso, a instncia (876, 145, 323, 112, 221) ter tamanho 15 ou, se o leitor assim
preferir, 16.)

1.2

Consumo de tempo de algoritmos

Dizemos que um algoritmo resolve um problema se, ao receber a descrio de uma


instncia do problema, devolve uma soluo da instncia (ou informa que a instncia
no tem soluo). Para cada instncia do problema, o algoritmo consome uma quantidade de tempo diferente. Digamos que o algoritmo consome T (I) unidades de tempo
para processar a instncia I. A relao entre T (I) e o tamanho de I d uma medida da
eficincia do algoritmo.
Em geral, um problema tem muitas instncias diferentes de um mesmo tamanho.
Isto exige a introduo dos conceitos de pior caso e melhor caso. Dado um algoritmo A para o problema e um nmero natural n, seja T (n) o mximo de T (I) para
todas as instncias I de tamanho n do problema. Dizemos que
T mede o consumo de tempo de A no pior caso.
De modo anlogo, seja T (n) o mnimo de T (I) para todas as instncia I de tamanho n.
Dizemos que T mede o consumo de A no melhor caso.
Por exemplo, um algoritmo pode consumir 200n unidades de tempo no melhor
caso e 10n2 + 100n unidades no pior. (Estou ignorando os valores pequenos de n, para
os quais 200n maior que 10n2 + 100n.)
Nas nossas anlises, suporemos quase sempre (o Captulo 7 uma exceo) que
uma execuo de cada linha de pseudocdigo consome uma quantidade de tempo que
no depende do tamanho da instncia submetida ao algoritmo. (Para isso, ser necessrio descrever os algoritmos de maneira suficientemente detalhada.) Em particular,
suporemos quase sempre que o consumo de tempo das operaes aritmticas (adio,
multiplicao, comparao, atribuio, etc.) no depende do tamanho dos nmeros
envolvidos.

ANLISE DE ALGORITMOS

1.3

11

Recurso e algoritmos recursivos

Muitos problemas computacionais tm a seguinte propriedade: cada soluo de uma


instncia do problema contm solues de instncias menores do mesmo problema.
Dizemos que tais problemas tm estrutura recursiva. Para resolver um problema desse
tipo, aplique o seguinte mtodo: se a instncia dada pequena, resolva-a diretamente
(use fora bruta se necessrio); se a instncia grande,
1. reduza-a a uma instncia menor,
2. encontre uma soluo S da instncia menor,
3. use S para construir uma soluo da instncia original.
A aplicao desse mtodo produz um algoritmo recursivo.
Para provar que um algoritmo recursivo est correto, basta fazer uma induo matemtica no tamanho das instncias. Antes de empreender a prova, essencial colocar
no papel, de maneira precisa e completa, a relao entre o que o algoritmo recebe e
o que devolve.
Exemplo 1: soma dos elementos positivos de um vetor. O seguinte algoritmo
recursivo recebe um vetor A[1 . . n] de nmeros inteiros, com n 0, e devolve a soma
dos elementos positivos do vetor:3
S OMA P OSITIVOS (A, n)
1 se n = 0
2
ento devolva 0
3
seno s S OMA P OSITIVOS (A, n 1)
4
se A[n] > 0
5
ento devolva s + A[n]
6
seno devolva s
A prova da correo do algoritmo uma induo em n. Se n = 0, evidente que
o algoritmo d a resposta correta. Agora tome n 1. Podemos supor, por hiptese de
induo, que S OMA P OSITIVOS com argumentos A e n 1 produz o resultado prometido. Portanto, no incio da linha 4, s a soma dos elementos positivos de A[1 . . n1].
A partir de s, as linhas 4 a 6 calculam corretamente a soma dos elementos positivos de
A[1 . . n].
Exemplo 2: logaritmo truncado. O piso de um nmero no negativo x o nico
nmero natural i tal que i x < i + 1. O piso de x denotado por bxc.
bxc
Para todo nmero natural n 1, o piso do logaritmo de n na base 2, denotado por lg n
blg nc, o nico nmero natural k tal que 2k n < 2k+1 .
O seguinte algoritmo recursivo recebe um nmero natural n 1 e devolve blg nc:
3

Usaremos a excelente notao do livro de Cormen et al. [3] para descrever algoritmos.

12

FEOFILOFF

P ISO D E L OG (n)
1 se n = 1
2
ento devolva 0
3
seno devolva P ISO D E L OG (bn/2c) + 1
Prova da correo do algoritmo: Se n = 1, evidente que o algoritmo devolve o
valor correto de blg nc. Agora tome n 2 e seja k o nmero blg nc. Queremos mostrar
que o algoritmo devolve k.
Como 2k n < 2k+1 , temos 2k1 n/2 < 2k . Como 2k1 um nmero natural,
temos 2k1 bn/2c < 2k e portanto blgbn/2cc = k 1. Como bn/2c < n, podemos
supor, por hiptese de induo, que o valor da expresso P ISO D E L OG (bn/2c) k 1.
Portanto, o algoritmo devolve k 1 + 1 = k, como queramos provar.

1.4
N
N>
R
R
R>
dxe

Convenes de notao

Para concluir esta introduo, estabelecemos algumas convenes de notao. Denotaremos por N o conjunto {0, 1, 2, 3, . . .} dos nmeros naturais (que coincide com o dos
inteiros no negativos). O conjunto N {0} ser denotado por N> . O conjunto dos
nmeros reais ser denotado por R. O conjunto dos reais no negativos e o dos reais
estritamente positivos sero denotados por R e por R> respectivamente.
Como j dissemos acima, o piso de um nmero x em R o nico nmero i em N
tal que i x < i + 1. O teto de x o nico nmero j em N tal que j 1 < x j. O piso
e o teto de x so denotados por bxc e dxe respectivamente.
Denotaremos por lg n o logaritmo de um nmero n na base 2. Portanto, lg n =
log2 n.

Captulo 2

Comparao assinttica de funes


desejvel exprimir o consumo de tempo de um algoritmo de uma maneira que no
dependa da linguagem de programao, nem dos detalhes de implementao, nem do
computador empregado. Para tornar isto possvel, preciso introduzir um modo grosseiro de comparar funes. (Estou me referindo s funes no sentido matemtico da
palavra que exprimem a dependncia entre o consumo de tempo de um algoritmo e
o tamanho de sua entrada.)
Essa comparao grosseira s leva em conta a velocidade de crescimento das
funes. Assim, ela despreza fatores multiplicativos (pois a funo 2n2 , por exemplo,
cresce to rpido quanto 10n2 ) e despreza valores pequenos do argumento (a funo
n2 cresce mais rpido que 100n, embora n2 seja menor que 100n quando n pequeno).
Dizemos que esta maneira de comparar funes assinttica.
H trs tipos de comparao assinttica: uma com sabor de , outra com sabor
de , e uma terceira com sabor de =.

2.1

Notao O

Dadas funes F e G de N em R , dizemos que F est em O(G) se existem c e n0 em N>


tais que
F (n) c G(n)
para todo n n0 . A mesma coisa pode ser dita assim: existe c em N> tal que F (n)
c G(n) para todo n suficientemente grande. Em lugar de F est em O(G), podemos
dizer F O(G), F O(G) e at F = O(G).
Exemplo 1: 100n est em O(n2 ), pois 100n n n = n2 para todo n 100.
Exemplo 2: 2n3 +100n est em O(n3 ). De fato, para todo n 1 temos 2n3 +100n
2n3 + 100n3 102n3 . Eis outra maneira de provar que 2n3 + 100n est em O(n3 ): para
todo n 100 tem-se 2n3 + 100n 2n3 + n n n = 3n3 .
Exemplo 3: n1.5 est em O(n2 ), pois n1.5 n0.5 n1.5 = n2 para todo n 1.
Exemplo 4: n2 /10 no est em O(n). Eis uma prova deste fato. Tome qualquer c
13

14

FEOFILOFF

em N> . Para todo n > 10c temos n2 /10 = n n/10 > 10c n/10 = cn. Logo, no
verdade que n2 /10 cn para todo n suficientemente grande.
Exemplo 5: 2n est em O(2n ). De fato, 2n 2n para todo n 1, como provaremos
por induo em n. Prova: Se n = 1, a afirmao verdadeira pois 2 1 = 21 . Agora
tome n 2 e suponha, a ttulo de hiptese de induo, que 2(n 1) 2n1 . Ento
2n 2(n + n 2) = 2(n 1) + 2(n 1) 2n1 + 2n1 = 2n , como queramos
demonstrar.
A seguinte regra da soma til: se F e F 0 esto ambas em O(G) ento F + F 0
tambm est em O(G). Eis uma prova da regra. Por hiptese, existem nmeros c
e n0 tais que F (n) cG(n) para todo n n0 . Analogamente, existem c0 e n00 tais
que F 0 (n) c0 G(n) para todo n n00 . Ento, para todo n max(n0 , n00 ), tem-se
F (n) + F 0 (n) (c + c0 )G(n).
Exemplo 6: Como 2n3 e 100n esto ambas em O(n3 ), a funo 2n3 + 100n tambm
est em O(n3 ).
Nossa definio da notao O foi formulada para funes de N em R , mas ela pode
ser estendida, da maneira bvia, a funes que no esto definidas ou so negativas
para valores pequenos do argumento.
Exemplo 7: Embora n2 100n no esteja em R quando n < 100, podemos dizer
que n2 100n O(n2 ), pois n2 100n n2 para todo n 100.
Exemplo 8: Embora lg n no esteja definida quando n = 0, podemos dizer que lg n
est em O(n). De fato, se tomarmos o logaritmo da desigualdade n 2n do Exemplo 5,
veremos que lg n n para todo n 1.
Exemplo 9: n lg n est em O(n2 ). Segue imediatamente do Exemplo 8.

Exerccios
2.1 Critique a afirmao n2 100n est em O(n2 ) para todo n 100.
2.2 Mostre que lg n est em O(n0.5 ).

2.2

Notao mega

Dadas funes F e G de N em R , dizemos que F est em (G) se existe c em N> tal


que
1
F (n) G(n)
c
para todo n suficientemente grande. claro que inversa de O, ou seja, uma
funo F est em (G) se e somente se G est em O(F ).
Exemplo 10: n3 + 100n est em (n3 ), pois n3 + 100n n3 para todo n.
A definio da notao pode ser estendida, da maneira bvia, a funes F ou G
que esto definidas e so no negativas apenas para valores grandes de n.

15

ANLISE DE ALGORITMOS

n2

Exemplo 11: n2 2n (n2 ). De fato, temos 2n 21 n2 para todo n 4 e portanto


2n n2 12 n2 = 12 n2 .

Exemplo 12: n lg n est em (n).


portanto n lg n n.

De fato, para todo n 2 tem-se lg n 1 e

Exemplo 13: 100n no est em (n2 ). Tome qualquer c em N> . Para todo n >
100c, tem-se 100 < 1c n e portanto 100n < 1c n2 .
Exemplo 14: n no (2n ). Basta mostrar que para qualquer c em N> tem-se
n < 1c 2n para todo n suficientemente grande. Como todo c menor que alguma potncia de 2, basta mostrar que, para qualquer k em N> , tem-se n 2k 2n para todo n
suficientemente grande. Especificamente, mostraremos que n 2nk para todo n 2k.
A prova por induo em n. Se n = 2k, temos k 2k1 conforme o Exemplo 5
com k no papel de n, e portanto n = 2k 2 2k1 = 2k = 22kk = 2nk . Agora tome
n 2k + 1 e suponha, a ttulo de hiptese de induo, que n 1 2n1k . Ento
n n + n 2 = n 1 + n 1 = 2 (n 1) 2 2n1k = 2nk , como queramos
demonstrar.

Exerccios
2.3 Mostre que 2n1 est em (2n ).
2.4 Mostre que lg n no (n).

2.3

Notao Teta

Dizemos que F est em (G) se F est em O(G) e tambm em (G), ou seja, se existem
c e c0 em N> tais que
1
G(n) F (n) c0 G(n)
c
para todo n suficientemente grande. Se F est em (G), diremos que F proporcional
a G, ainda que isto seja um tanto incorreto.
Exemplo 15: Para qualquer a em R> e qualquer b em R, a funo an2 + bn est
em (n2 ).

Exerccio
2.5 Mostre que n(n + 1)/2 e n(n 1)/2 esto em (n2 ).

2.4

Consumo de tempo de algoritmos

Seja A um algoritmo para um problema cujas instncias tm tamanho n. Se a funo


que mede o consumo de tempo de A no pior caso est em O(n2 ), por exemplo, podemos

16

FEOFILOFF

usar expresses como


A consome O(n2 ) unidades de tempo no pior caso
e A consome tempo O(n2 ) no pior caso. Podemos usar expresses semelhantes com
ou no lugar de O e melhor caso no lugar de pior caso.
(Se A consome tempo O(n2 ) no pior caso, tambm consome O(n2 ) em qualquer
caso. Analogamente, se consome (n2 ) no melhor caso, tambm consome (n2 ) em
qualquer caso. Mas no podemos dispensar a clusula no pior caso em uma afirmao como A consome tempo (n2 ) no pior caso.)
Linear, lineartmico, quadrtico. Um algoritmo linear se consome tempo (n)
no pior caso. fcil entender o comportamento de um tal algoritmo: quando o tamanho da entrada dobra, o algorimo consome duas vezes mais tempo; quando o tamanho multiplicado por uma constante c, o consumo de tempo tambm multiplicado
por c. Algoritmos lineares so considerados muito rpidos.
Um algoritmo lineartmico (ou ene-log-ene) se consome tempo (n lg n) no pior
caso. Se o tamanho da entrada dobra, o consumo dobra e acrescido de 2n; se o tamanho multiplicado por uma constante c, o consumo multiplicado por c e acrescido
de um pouco mais que cn.
Um algoritmo quadrtico se consome tempo (n2 ) no pior caso. Se o tamanho
da entrada dobra, o consumo quadruplica; se o tamanho multiplicado por uma
constante c, o consumo multiplicado por c2 .
Polinomial e exponencial. Um algoritmo polinomial se consome tempo O(nk )
no pior caso, sendo k um nmero natural. Por exemplo, polinomial qualquer algoritmo que consome O(n100 ) unidades de tempo. Apesar desse exemplo, algoritmos
polinomiais so considerados rpidos.
Um algoritmo exponencial se consome tempo (an ) no pior caso, sendo a um
nmero real maior que 1. Por exemplo, exponencial qualquer algoritmo que consome
(1.1n ) unidades de tempo. Se n multiplicado por 10, por exemplo, o consumo de
tempo de um tal algoritmo elevado potncia 10. Algoritmos exponenciais no so
polinomiais.

Exerccio
2.6 Suponha que dois algoritmos, A e B, resolvem um mesmo problema. Suponha que o tamanho das instncias do problema medido por um parmetro n. Em quais dos seguintes
casos podemos afirmar que A mais rpido que B? Caso 1: A consome tempo O(lg n) no
pior caso e B consome tempo O(n3 ) no pior caso. Caso 2: A consome O(n2 lg n) unidades de tempo no pior caso e B consome (n2 ) unidades de tempo no pior caso. Caso 3:
No pior caso, A consome O(n2 ) unidades de tempo e B consome (n2 lg n) unidades de
tempo.

Captulo 3

Soluo de recorrncias
A habilidade de resolver recorrncias importante para a anlise do consumo de tempo
de algoritmos recursivos. Uma recorrncia uma frmula que define uma funo,
digamos F , em termos dela mesma. Mais precisamente, define F (n) em termos de
F (n 1), F (n 2), F (n 3), etc.
Uma soluo de uma recorrncia uma frmula que exprime F (n) diretamente em
termos de n. Para as aplicaes anlise de algoritmos, uma frmula exata para F (n)
no necessria: basta mostrar que F est em (G) para alguma funo G definida
explicitamente em termos de n.

3.1

Exemplo 1

Seja F uma funo de N em R> . Suponha que F (1) = 1 e F satisfaz a recorrncia


F (n) = 2F (n 1) + 1

(3.1)

para todo n 2. Eis alguns valores da funo: F (2) = 3, F (3) = 7, F (4) = 15. fcil
desenrolar a recorrncia:
F (n) = 2F (n 1) + 1
= 2(2F (n 2) + 1) + 1
= 4F (n 2) + 3
=
= 2j F (n j) + 2j 1
= 2n1 F (1) + 2n1 1 .
Conclumos assim que
F (n) = 2n 1

(3.2)

para todo n 1. (No temos informaes sobre o valor de F (0).) Portanto, F est
em (2n ).

17

18

FEOFILOFF

Exerccios
3.1 Confira a frmula (3.2) por induo em n.
3.2 Sejam a, b e n0 trs nmeros naturais e suponha que F (n0 ) = a e F (n) = 2F (n 1) + b
para todo n > n0 . Mostre que F est em (2n ).

3.2

Exemplo 2

Suponha que uma funo F de N em R> satisfaz a seguinte recorrncia:


F (n) = F (n 1) + n

(3.3)

para todo n 2. Suponha ainda que F (1) = 1. Teremos, em particular, F (2) = F (1) +
2 = 3 e F (3) = F (2) + 3 = 6.
A recorrncia pode ser facilmente desenrolada: F (n) = F (n1) + n = F (n2) +
(n1)+n = = F (1)+2+3+ +(n1)+n = 1+2+3+ +(n1)+n. Conclumos
assim que
F (n) = 12 (n2 + n)
(3.4)
para todo n 1. (No temos informaes sobre o valor de F (0).) Portanto, F est
em (n2 ).
Recorrncias semelhantes. O valor de F (1) tem pouca influncia sobre o resultado. Se tivssemos F (1) = 10, por exemplo, a frmula (3.4) seria substituda por
F (n) = 21 (n2 + n) + 9, e esta funo tambm est em (n2 ).
O ponto a partir do qual (3.3) comea a valer tambm tem pouca influncia sobre a
soluo da recorrncia. Se (3.3) valesse apenas a partir de n = 5, por exemplo, teramos
F (n) = 21 (n2 + n) + F (4) 10 no lugar de (3.4), e esta funo tambm est em (n2 ).

Exerccios
3.3 Confira (3.4) por induo em n.
3.4 Suponha que F satisfaz a recorrncia F (n) = F (n 1) + 3n + 2 para n = 2, 3, 4, . . . Mostre
que se F (1) = 1 ento F (n) = 3n2 /2 + 7n/2 4 para todo n 2. Conclua que F est
em (n2 ).
3.5 Sejam a, b e c trs nmeros naturais e suponha que F satisfaz as seguintes condies:
F (n0 ) = a e F (n) = F (n 1) + bn + c para todo n > n0 . Mostre que F est em (n2 ).
3.6 Suponha que F (n) = F (n 1) + 7 para n = 2, 3, 4, . . . Mostre que se F (1) = 1 ento
F (n) = 7n 6 para todo n 1. Conclua que F est em (n).

3.3

Exemplo 3

Seja F uma funo que leva N em R> . Suponha que F satisfaz a recorrncia
F (n) = 2F (bn/2c) + n

(3.5)

19

ANLISE DE ALGORITMOS

para todo n 2. (No faz sentido trocar bn/2c por n/2 pois n/2 no est em N
quando n mpar.) Suponha ainda que F (1) = 1 (e portanto F (2) = 4, F (3) = 5, etc.)
mais fcil entender (3.5) quando n uma potncia de 2, pois nesse caso bn/2c se
reduz a n/2. Se n = 2j , temos
F (2j ) = 2F (2j1 ) + 2j
= 22 F (2j2 ) + 21 2j1 + 2j
= 23 F (2j3 ) + 22 2j2 + 21 2j1 + 2j
= 2j F (20 ) + 2j1 21 + + 22 2j2 + 21 2j1 + 20 2j
= 2j 20 + 2j1 21 + + 22 2j2 + 21 2j1 + 20 2j
= (j + 1)2j
= j2j + 2j .

(3.6)

Para ter certeza, podemos conferir esta frmula por induo em j. Se j = 1, temos
F (2j ) = 4 = (j + 1)2j . Agora tome j 2. De acordo com (3.5), F (2j ) = 2F (2j1 ) + 2j .
Por hiptese de induo, F (2j1 ) = 2j1 j. Logo, F (2j ) = 2 2j1 j + 2j = 2j j + 2j , como
queramos mostrar.
Como 2j = n, a expresso (3.6) pode ser reescrita assim:
F (n) = n lg n + n

(3.7)

quando n potncia de 2. Embora esta frmula s se aplique s potncias de 2, podemos us-la para obter cotas superior e inferior vlidas para todo n suficientemente
grande. O primeiro passo nessa direo verificar que F crescente, ou seja, que
F (n) < F (n + 1)

(3.8)

para todo n 1. A prova uma induo em n. Se n = 1, temos F (n) = 1 < 4 =


F (n + 1). Agora tome n 2. Se n par ento F (n) < F (n) + 1 = 2F ( n2 ) + n + 1 =
2F (b n+1
2 c)+n+1 = F (n+1), em virtude de (3.5). Agora suponha n mpar. Por hiptese
n1
n+1
de induo, F ( n1
2 ) F ( 2 + 1) = F ( 2 ). Logo, por (3.5),
n+1
n+1
F (n) = 2F ( n1
2 ) + n 2F ( 2 ) + n < 2F ( 2 ) + n + 1 = F (n + 1) .

Mostramos assim que F crescente.


Agora podemos calcular uma boa cota superior para F a partir de (3.7). Mostraremos que
F (n) 6n lg n
(3.9)
para todo n 2. Tome o nico j em N tal que 2j n < 2j+1 . Em virtude de (3.8),
F (n) < F (2j+1 ). Em virtude de (3.6), F (2j+1 ) = (j + 2)2j+1 3j2j+1 = 6j2j . Como
j lg n, temos 6j2j 6n lg n.
Uma boa cota inferior para F tambm pode ser calculada a partir de (3.7): mostraremos que
F (n) 12 n lg n
(3.10)

20

FEOFILOFF

para todo n 2. Tome o nico j em N tal que 2j n < 2j+1 . Em virtude de (3.8)
e (3.6), temos F (n) F (2j ) = (j + 1)2j = 21 (j + 1)2j+1 . Como lg n < j + 1, temos
1
j+1 > 1 n lg n.
2 (j + 1)2
2
De (3.9) e (3.10), conclumos que F est em (n lg n).
Recorrncias semelhantes. O ponto n0 a partir do qual a recorrncia (3.5) comea
a valer, bem como os valores de F (1), F (2), . . . , F (n0 1), tm pouca influncia sobre a soluo da recorrncia: quaisquer que sejam esses valores iniciais, F estar em
(n lg n). Se (3.5) vale apenas para n 3, por exemplo, teremos n lg n + F (2)2
n no
2
lugar de (3.7).
A parcela n na expresso 2F (bn/2c)+n tambm pode ser ligeiramente alterada sem
que F saia de (n lg n). Assim, quaisquer que sejam c > 0 e d, se F (n) = 2F (bn/2c) +
cn + d ento F est em (n lg n).
Finalmente, podemos trocar 2F (bn/2c) por 2F (dn/2e) ou at mesmo por
F (bn/2c) + F (dn/2e) sem que F saia de (n lg n).
Mas o fator 2 que multiplica F (bn/2c) crtico: se este fator for alterado, a funo
F deixar de pertencer a (n lg n).

Exerccios
3.7 Suponha que um funo F de N em R> satisfaz a recorrncia F (n) = F (bn/2c) + 1 para
todo n 2. Mostre que F est em (lg n).
3.8 Seja F uma funo de N em R> tal que F (n) = 2F (bn/2c) + 1 para todo n 2. Mostre que
F est em (n).
3.9 Seja F um funo de N em R> tal que F (n) = 4F (bn/2c) + n quando n 2. Mostre que
F est em (n2 ). Sugesto: mostre que 41 n2 F (n) 8n2 para todo n suficientemente
grande.

3.4

Exemplo 4

Seja F um funo de N em R> . Suponha que


F (n) = 3F (bn/2c) + n

(3.11)

para todo n 2. Suponha ainda que F (1) = 1. Para comear a entender o comportamento de F , considere os valores de n que so potncias de 2. Quando n = 2j , temos
F (2j ) = 3F (2j1 ) + 2j
= 32 F (2j2 ) + 31 2j1 + 2j
= 33 F (2j3 ) + 32 2j2 + 31 2j1 + 2j
= 3j F (20 ) + 3j1 21 + + 32 2j2 + 31 2j1 + 30 2j
= 3j 20 + 3j1 21 + + 32 2j2 + 31 2j1 + 30 2j

21

ANLISE DE ALGORITMOS

= 2j (3/2)j + (3/2)j1 + + (3/2)2 + (3/2)1 + (3/2)0


= 2j

(3/2)j+1 1
3/2 1

= 2j+1 (3/2)j+1 1

= 3j+1 2j+1 .

(3.12)

Observe que 3j = (2lg 3 )j = (2j )lg 3 = nlg 3 . (A ttulo de curiosidade, lg 3 fica entre 1.584
e 1.585.) Portanto, a frmula (3.12) pode ser reescrita assim:
F (n) = 3nlg 3 2n
para toda potncia n de 2. Embora esta frmula s valha para as potncias de 2, podemos us-la para obter cotas superior e inferior vlidas para todo n suficientemente
grande. A primeira providncia nessa direo certificar-se de que F crescente:
F (n) < F (n + 1)
para todo n 1. A prova anloga de (3.8). Agora estamos em condies de calcular
uma boa cota superior para F :
F (n) 9nlg 3
(3.13)
para todo n 1. Tome j em N tal que 2j n < 2j+1 . Como F crescente, (3.12) garante
que F (n) < F (2j+1 ) = 3j+2 2j+2 3j+2 = 9 (2j )lg 3 9nlg 3 , como queramos
mostrar. Tambm podemos calcular uma boa cota inferior:
F (n) 31 nlg 3

(3.14)

para todo n 1. Tome j em N tal que 2j n < 2j+1 . Como F crescente, (3.12) garante
que F (n) F (2j ) = 3j+1 2j+1 = 3j + 2 3j 2 2j 3j = 13 3j+1 = 13 (2j+1 )lg 3 > 31 nlg 3 ,
como queramos demonstrar.
As relaes (3.13) e (3.14) mostram que F est em (nlg 3 ).
Recorrncias semelhantes. Se (3.11) valesse apenas quando n n0 , a funo F
continuaria em (nlg 3 ) quaisquer que fossem os valores de F (bn0 /2c), F (bn0 /2c + 1),
. . . , F (n0 1).
Alm disso, F continuar em (nlg 3 ) se (3.11) for substituda por F (n) =
3F (bn/2c) + cn + d, quaisquer que sejam c > 0 e d. Tambm continuar em (nlg 3 ) se
3F (bn/2c) for trocado por 2F (bn/2c) + F (dn/2e) ou at mesmo por 2F (bn/2c) +
F (dn/2e + 1).

Exerccio
3.10 Confira a formula (3.12) por induo em j.

22

3.5

FEOFILOFF

Teorema mestre

O seguinte teorema d a soluo de muitas recorrncias semelhantes s das Sees 3.3


e 3.4. Sejam a, k e c nmeros em N> , N e R> respectivamente. Seja F uma funo de N
em R> tal que
n
F (n) = a F
+ cnk
(3.15)
2
para n = 21 , 22 , 23 , . . . Suponha ainda que F assintoticamente no decrescente, ou
seja, que existe n1 tal que F (n) F (n + 1) para todo n n1 . Nessas condies,
se lg a > k ento F est em (nlg a ),
se lg a = k ento F est em

(nk

se lg a < k ento F est em

(nk ).

lg n),

(3.16)
(3.17)
(3.18)

(Recorrncias como (3.15) aparecem na anlise de algoritmos baseados na estratgia da diviso e conquista: dada uma instncia de tamanho n, divida a instncia em a
partes de tamanho n/2, resolva essas subinstncias, e combine as solues em tempo
limitado por cnk .)
Generalizao. O teorema pode ser generalizado como segue. Sejam a 1, b 2,
k 0 e n0 1 nmeros em N e seja c um nmero em R> . Seja F uma funo de N
em R> tal que
n
F (n) = a F
+ cnk
(3.19)
b
para n = n0 b1 , n0 b2 , n0 b3 , . . . Suponha ainda que F assintoticamente no decrescente.
Nessas condies,
se lg a/ lg b > k ento F est em (nlg a/ lg b ),
se lg a/ lg b = k ento F est em

(nk

se lg a/ lg b < k ento F est em

(nk ).

lg n),

(3.20)
(3.21)
(3.22)

A prova deste teorema pode ser encontrada na Seo 4.7 do livro de Brassard e
Bratley [2] e na Seo 4.4 do livro de Cormen et al. [3].
Exemplo A. Seja c um nmero em R> e seja F uma funo de N em R> tal que
F (n) = F (bn/2c) + 2F (dn/2e) + cn para todo n 2. Nessas condies, F no decrescente e portanto (3.16) garante que F est em (nlg 3 ). (Compare com o resultado da
Seo 3.4.)
Exemplo B. Sejam a e k nmeros em N tais que a > 2k e seja c um nmero em R> .
Seja F uma funo de N em R> tal que F (n) = aF bn/2c + cnk para todo n 1.
Nessas condies, F no decrescente e portanto (3.16) garante que F est em (nlg a ).

ANLISE DE ALGORITMOS

23

Notas bibliogrficas
Este captulo foi baseada na Seo 4.7 do livro de Brassard e Bratley [2]. Veja tambm o
verbete Master theorem na Wikipedia.

24

FEOFILOFF

Captulo 4

Ordenao de vetor
Um vetor A[p . . r] crescente se A[p] A[p + 1] A[r]. A tarefa de colocar
um vetor em ordem crescente um dos problemas computacionais mais conhecidos e
bem-estudados.
Problema da Ordenao: Rearranjar um vetor A[p . . r] em ordem crescente.

4.1

Algoritmo Mergesort

O seguinte algoritmo uma soluo eficiente do Problema da Ordenao:


M ERGE S ORT (A, p, r)
1 se p < r
2
ento q b(p + r)/2c
3
M ERGE S ORT (A, p, q)
4
M ERGE S ORT (A, q+1, r)
5
I NTERCALA (A, p, q, r)
A rotina I NTERCALA rearranja o vetor A[p . . r] em ordem crescente supondo que os
subvetores A[p . . q] e A[q+1 . . r] so ambos crescentes.
O algoritmo est correto. Adote o nmero n := r p + 1 como tamanho da instncia (A, p, r) do problema. Se n 1, o vetor tem no mximo 1 elemento e portanto
no fazer nada a ao correta. Suponha agora que n 2. Nas linhas 3 e 4, o algoritmo aplicado a instncias do problema que tm tamanho estritamente menor que n
(tamanho dn/2e na linha 3 e tamanho bn/2c na linha 4). Assim, podemos supor, por
hiptese de induo, que no incio da linha 5 os vetores A[p . . q] e A[q+1 . . r] esto em
ordem crescente. Graas ao de I NTERCALA, A[p . . r] estar em ordem crescente no
fim da linha 5.

25

26

FEOFILOFF

p
111

333

555

555

777

q+1

888

222

r
444

777

999

999

Figura 4.1: Vetor A no incio da linha 5 do algoritmo.

Consumo de tempo. Seja T (n) o tempo que o algoritmo consome, no pior caso,
para processar uma instncia de tamanho n. Ento
T (n) = T (dn/2e) + T (bn/2c) + n .
As parcelas T (d n2 e) e T (b n2 c) correspondem s linhas 3 e 4. A parcela n representa o
consumo de tempo da linha 5, uma vez que o algoritmo I NTERCALA pode ser implementado de maneira a consumir tempo proporcional a n. (Veja o Exerccio 4.1 abaixo.)
Como vimos nas Sees 3.3 e 3.5, a funo T est em
(n lg n) .
O consumo de tempo do algoritmo no melhor caso tambm est em (n lg n).

Exerccio
4.1 Descreva em pseudocdigo o algoritmo I NTERCALA mencionado acima. Mostre que o
consumo de tempo do algoritmo (n).

4.2

Diviso e conquista

O algoritmo M ERGE S ORT emprega a estratgia da diviso e conquista: a instncia original do problema dividida em duas instncias menores, essas instncias so resolvidas
recursivamente, e as solues so combinadas para produzir uma soluo da instncia
original.
O segredo do sucesso est no fato de que o processo de diviso (que est na linha 2,
nesse caso) e o processo da combinao (que acontece na linha 5) consomem pouco
tempo.
A estratgia da diviso e conquista rende algoritmos eficientes para muitos problemas. Veremos exemplos nos captulos seguintes.

Captulo 5

Segmento de soma mxima


Imagine uma grandeza que evolui com o tempo, aumentando ou diminuindo uma vez
por dia, de maneira irregular. Dado o registro das variaes dirias desta grandeza
ao longo de um ano, queremos encontrar um intervalo de tempo em que a variao
acumulada tenha sido mxima. Este captulo, inspirado no livro de Bentley [1], estuda
trs algoritmos para o problema. Cada algoritmo mais eficiente que o anterior; cada
algoritmo usa uma estratgia diferente.

5.1

O problema

Um segmento de um vetor A[p . . r] qualquer subvetor da forma A[i . . k], com p i


k r. A condio i k garante que o segmento no vazio.1 A soma de um segmento
A[i . . k] o nmero A[i] + A[i + 1] + + A[k].
A solidez de um vetor A[p . . r] a soma de um segmento de soma mxima. (O
termo solidez apenas uma convenincia local e no ser usado fora deste captulo.)
Problema do Segmento de Soma Mxima: Calcular a solidez de um vetor
A[p . . r] de nmeros inteiros.
Se o vetor no tem elementos negativos, sua solidez a soma de todos os elementos.
Por outro lado, se todos os elementos so negativos ento a solidez do vetor o valor
de seu elemento menos negativo.

20

30

15

10

30

20

30

30

Figura 5.1: A cor mais clara destaca um segmento de soma mxima.


A solidez do vetor 35.

1
Teria sido mais limpo e natural aceitar segmentos vazios. Mas a discusso fica ligeiramente mais
simples se nos limitarmos aos segmentos no vazios.

27

28

5.2

FEOFILOFF

Primeiro algoritmo

Se aplicarmos cegamente a definio de solidez, teremos que examinar todos os pares


ordenados (i, j) tais que p i j r. Esse algoritmo consumiria (n3 ) unidades de
tempo. Mas possivel fazer algo mais eficiente:
S OLIDEZ I (A, p, r)
1
x A[r]
2
para q r 1 decrescendo at p faa
3
s0
4
para j q at r faa
5
s s + A[j]
6
se s > x ento x s
7
devolva x
O algoritmo est correto. A cada passagem pela linha 2, imediatamente antes da
comparao de q com p,
x a solidez do vetor A[q+1 . . r].
Este invariante mostra que o algoritmo est correto, pois na ltima passagem pela linha 2 teremos q = p 1 e ento x ser a solidez do A[p . . r].
Consumo de tempo. Adote n := r p + 1 como medida do tamanho da instncia
A[p . . r] do nosso problema. O consumo de tempo do algoritmo ser medido em relao
a n.
Podemos supor que uma execuo de qualquer das linhas do algoritmo consome
uma quantidade de tempo que no depende de n. Para cada valor fixo de q, o bloco de
linhas 5-6 repetido r q + 1 vezes. Como q decresce de r 1 at p, o nmero total de
repeties do bloco de linhas 5-6
r1
X

(r q + 1) = n + (n 1) + + 3 + 2 =

2
1
2 (n

+ n 2) .

q=p

Portanto, o consumo de tempo est em (n2 ), tanto no pior quanto no melhor caso.
O algoritmo ineficiente porque a soma de cada segmento recalculada muitas vezes. Por exemplo, a soma de A[10 . . r] refeita durante o clculo das somas de A[9 . . r],
A[8 . . r], etc. O algoritmo da prxima seo procura remediar esta ineficincia.

Exerccios
5.1 Modifique o algoritmo S OLIDEZ I de modo que ele devolva um par (i, k) de ndices tal que
a soma A[i] + + A[k] a solidez de A[p . . r].
5.2 Escreva um algoritmo anlogo a S OLIDEZ I para tratar da variante do problema que admite
segmentos vazios. Nessa variante, um segmento A[i . . k] vazio se i = k + 1. A soma de
um segmento vazio 0.

29

ANLISE DE ALGORITMOS

5.3

Segundo algoritmo: diviso e conquista

Nosso segundo algoritmo usa a estratgia da diviso e conquista (veja a Seo 4.2),
que consiste em dividir a instncia dada ao meio, resolver cada uma das metades e
finalmente juntar as duas solues. O algoritmo devolve a solidez do vetor A[p . . r]
supondo p r:
S OLIDEZ II (A, p, r)
1 se p = r
2
ento devolva A[p]
3
seno q b(p + r)/2c
4
x0 S OLIDEZ II (A, p, q)
5
x00 S OLIDEZ II (A, q + 1, r)
6
y 0 s A[q]
7
para i q 1 decrescendo at p faa
8
s A[i] + s
9
se s > y 0 ento y 0 s
10
y 00 s A[q + 1]
11
para j q + 2 at r faa
12
s s + A[j]
13
se s > y 00 ento y 00 s
14
x max (x0 , y 0 + y 00 , x00 )
15
devolva x
O algoritmo est correto. Seja n := r p + 1 o nmero de elementos do vetor
A[p . . r]. Se n = 1, claro que a resposta do algoritmo est correta. Suponha agora que
n 2. Depois da linha 4, por hiptese de induo, x0 a solidez de A[p . . q]. Depois da
linha 5, x00 a solidez de A[q+1 . . r]. Depois do bloco de linhas 6-13, y 0 + y 00 a maior
soma da forma A[i] + + A[j] com i q < j. (Veja o Exerccio 5.3.)
Em suma, y 0 + y 00 cuida dos segmentos que contm A[q] e A[q+1], enquanto x0 e x00
cuidam de todos os demais segmentos. Conclumos assim que o nmero x calculado
na linha 14 a solidez de A[p . . r].

p
20

30

15

q
10

q+1
30

20

30

r
30

Figura 5.2: Incio da linha 14 do algoritmo S OLIDEZ II.


Nesse ponto, x0 = 20, x00 = 30, y 0 = 5 e y 00 = 30.

Consumo de tempo. Seja T (n) o consumo de tempo do algoritmo no pior caso


quando aplicado a um vetor de tamanho n. O bloco de linhas 6 a 13 examina todos os

30

FEOFILOFF

elementos de A[p . . r] e portanto consome tempo proporcional a n. Temos ento


T (n) = T (dn/2e) + T (bn/2c) + n .
A parcela T (dn/2e) descreve o consumo da linha 4 e a parcela T (bn/2c) descreve o consumo da linha 5. Esta recorrncia j foi discutida nas Sees 3.3 e 3.5, onde mostramos
que T est em
(n lg n) .
O algoritmo S OLIDEZ II mais eficiente que S OLIDEZ I pois n lg n O(n2 ) enquanto
n2 no O(n lg n). Mas S OLIDEZ II tem suas prprias ineficincias, pois refaz alguns
clculos diversas vezes (por exemplo, a soma de A[i . . q] nas linhas 6-9 j foi calculada
durante a execuo da linha 4). A prxima seo procura eliminar estas ineficincias.

Exerccio
5.3 Prove que depois do bloco de linhas 6-13 do algoritmo S OLIDEZ II, y 0 + y 00 a maior soma
dentre todas as que tm a forma A[i] + + A[j] com i q < j.

5.4

Terceiro algoritmo: programao dinmica

Nosso terceiro algoritmo usa a tcnica da programao dinmica, que consiste em armazenar os resultados de clculos intermedirios numa tabela para evitar que eles sejam repetidos.
Mas a tcnica no pode ser aplicada diretamente ao nosso problema. Ser preciso
tratar do seguinte problema auxiliar, que restringe a ateno aos segmentos terminais
do vetor: dado um vetor A[p . . r], encontrar a maior soma da forma
A[i] + + A[r] ,
com p i r. Para facilitar a discusso, diremos que a maior soma desta forma
a firmeza do vetor A[p . . r]. A solidez do vetor o mximo das firmezas de A[p . . r],
A[p . . r1], A[p . . r2], etc.
A firmeza do vetor tem uma propriedade recursiva que a solidez no tem. Suponha
que A[i]+ +A[r] a firmeza de A[p . . r]. Se i r1 ento A[i]+ +A[r1] a firmeza
de A[p . . r1]. (De fato, se A[p . . r1] tivesse firmeza maior ento existiria h r 1 tal
que A[h] + + A[r1] > A[i] + + A[r1] e portanto teramos A[h] + + A[r] >
A[i] + + A[r], o que impossvel.)
Se denotarmos a firmeza de A[p . . q] por F [q], podemos resumir a propriedade recursiva por meio de uma recorrncia: para qualquer vetor A[p . . r],

F [r] = max F [r1] + A[r] , A[r] .
(5.1)
Em outras palavras, F [r] = F [r 1] + A[r] e menos que F [r 1] seja negativo, caso em
que F [r] = A[r].
A recorrncia (5.1) serve de base para o seguinte algoritmo, que calcula a solidez
de A[p . . r] supondo p r:

31

ANLISE DE ALGORITMOS

S OLIDEZ III (A, p, r)


1 F [p] A[p]
2 para q p + 1 at r faa
3
se F [q 1] > 0
4
ento F [q] F [q1] + A[q]
5
seno F [q] A[q]
6 x F [p]
7 para q p + 1 at r faa
8
se F [q] > x ento x F [q]
9 devolva x
O algoritmo est correto. A cada passagem pela linha 2, imediatamente antes que
q seja comparado com r, F [q 1] a firmeza de A[p . . q1]. Mais que isso,
F [j] a firmeza de A[p . . j]

(5.2)

para j = q1, q2, . . . , p+1, p. Logo, no incio da linha 6, o fato (5.2) vale para j = p,
p + 1, . . . , r.
O bloco de linhas 6-8 escolhe a maior das firmezas. Portanto, no fim do algoritmo,
x a solidez de A[p . . r].
Consumo de tempo. O algoritmo consome tempo proporcional ao nmero de
elementos n := r p + 1 do vetor. O consumo de tempo do algoritmo est em
(n)
e o algoritmo , portanto, linear.

p
20

30

15

10

30

20

30

r
30

20

10

15

35

15

15

30

Figura 5.3: Vetores A e F no fim da execuo do algoritmo S OLIDEZ III.

Exerccios
5.4 Os dois processos iterativos de S OLIDEZ III podem ser fundidos num s, evitando-se assim
o uso do vetor F [p . . r]. Uma varivel f pode fazer o papel de um elemento genrico do
vetor F . Implemente essa ideia.
5.5 Suponha dada uma matriz A[1 . . n, 1 . . n] de nmeros inteiros (nem todos no negativos).
Encontrar uma submatriz quadrada de A que tenha soma mxima. (Veja o livro de Bentley [1, p.84].)

32

FEOFILOFF

5.5

Observaes sobre programao dinmica

O algoritmo S OLIDEZ III um exemplo de programao dinmica.2 A tcnica s se


aplica a problemas dotados de estrutura recursiva: qualquer soluo de uma instncia
deve conter solues de instncias menores. Assim, o ponto de partida de qualquer
algoritmo de programao dinmica uma recorrncia.
A caracterstica distintiva da programao dinmica a tabela que armazena as solues das vrias subinstncias da instncia original. (No nosso caso, trata-se da tabela
F [p . . r].) O consumo de tempo do algoritmo , em geral, proporcional ao tamanho da
tabela.
Os Captulos 8, 9 e 10 exibem outros exemplos de programao dinmica.

Notas bibliogrficas
Este captulo foi baseado no livro de Bentley [1].

Aqui, a palavra programao no tem relao direta com programao de computadores. Ela significa
planejamento e refere-se construo da tabela que armazena os resultados intermedirios usados para
calcular a soluo do problema.

Captulo 6

O problema da maioria
Imagine uma eleio com muitos candidatos e muitos eleitores. Como possvel determinar, em tempo proporcional ao nmero de eleitores, se algum dos candidatos obteve
a maioria1 dos votos?

6.1

O problema

Seja A[1 . . n] um vetor de nmeros naturais. Para qualquer nmero x, a cardinalidade


do conjunto {i : 1 i n, A[i] = x} o nmero de ocorrncias de x em A[1 . . n].
Diremos que x um valor majoritrio de A[1 . . n] se o nmero de ocorrncias de x
em A[1 . . n] maior que n/2. Assim, um valor majoritrio ocorre exatamente 21 (n + y)
vezes, sendo y um nmero natural no nulo que par se n par e mpar de n impar.
Problema da Maioria: Encontrar um valor majoritrio em um dado vetor
A[1 . . n].
Nem todo vetor tem um valor majoritrio. Mas se um valor majoritrio existe, ele
nico.
Poderamos ordenar o vetor A[1 . . n], contar o nmero de ocorrncias de cada elemento, e verificar se alguma dessas contagens supera n/2. A ordenao do vetor consome (n lg n) unidades de tempo se usarmos o algoritmo M ERGE S ORT (veja o Captulo 4).2 As contagens no vetor ordenado consomem (n). Portanto, o algoritmo todo
consumir (n lg n) unidades de tempo. primeira vista, parece mpossvel resolver
o problema em menos tempo.3 Mas existe um algoritmo que consome apenas O(n)
unidades de tempo, como mostraremos a seguir.
1
A popular expresso metade dos votos mais um incorreta pois a metade de um nmero mpar
no um nmero inteiro.
2
Sabe-se que todo algoritmo baseado em comparaes consome (n lg n) unidades tempo.
3
Se o nmero de possveis valores de A[1 . . n] fosse pequeno, conhecido a priori e independente de n,
poderamos usar um algoritmo do tipo bucket sort, que consome O(n) unidades de tempo.

33

34

FEOFILOFF

44

33

11

22

33

22

22

33

22

22

22

22

Figura 6.1: Este vetor tem um valor majoritrio?

6.2

Um algoritmo linear

Um algoritmo eficiente para o problema comea com a seguinte observao: se A[1 . . n]


tem um valor majoritrio e se A[n 1] 6= A[n] ento A[1 . . n2] tambm tem um valor majoritrio. (A observao se aplica igualmente a quaisquer dois elementos: se
A[i] 6= A[j] e A tem um valor majoritrio ento o vetor que se obtm pela eliminao
das posies i e j tambm tem um valor majoritrio.) Embora a intuio aceite esta
observao como verdadeira, sua demonstrao exige algum cuidado (veja a prova da
correo do algoritmo abaixo).
A recproca da observao no verdadeira. Por exemplo, (2, 5, 5, 1, 3) no tem
valor majoritrio, mas se retirarmos os dois ltimos elementos ento 5 passar a ser
um valor majoritrio.
Eis outra observao simples mas importante: para qualquer k no intervalo 1 . . n,
um nmero x valor majoritrio de A[1 . . n] se e somente se x majoritrio em
A[1 . . k1] ou em A[k . . n] ou em ambos. ( possvel, entretanto, que A[1 . . k1] e
A[k . . n] tenham valores majoritrios sem que A[1 . . n] tenha um valor majoritrio.)
Usaremos as duas observaes para obter um bom candidato a valor majoritrio.
Um bom candidato um nmero x com a seguinte propriedade: se o vetor tem um
valor majoritrio ento x esse valor. fcil verificar se um bom candidato , de fato,
majoritrio: basta percorrer o vetor e contar o nmero de ocorrncias do candidato. A
dificuldade est em obter um bom candidato em tempo O(n).
O seguinte algoritmo recebe um vetor A[1 . . n] de nmeros naturais, com n 1,
e devolve um valor majoritrio se tal existir. Se o vetor no tem valor majoritrio,
devolve 1 (note que o vetor no tem elementos negativos):
M AJORITRIO (A, n)
1 x A[1]
2 y1
3 para m 2 at n faa
4
se y 1
5
ento se A[m] = x
6
ento y y + 1
7
seno y y 1
8
seno x A[m]
9
y1

35

ANLISE DE ALGORITMOS

10
11
12
13
14
15
16

c0
para m 1 at n faa
se A[m] = x
ento c c + 1
se c > n/2
ento devolva x
seno devolva 1

O algoritmo est correto. A cada passagem pela linha 3, imediatamente antes da


comparao de m com n, temos os seguintes invariantes:
i. y 0 e
ii. existe k no intervalo 1 . . m1 tal que A[1 . . k1] no tem valor majoritrio
e x ocorre exatamente 12 (m k + y) vezes em A[k . . m1].
(Note que m k o nmero de elementos de A[k . . m1].) A validade de i bvia.
A validade de ii pode ser verificada como segue. No incio da primeira iterao, o
invariante ii vale com k = 1. Suponha agora que ii vale no incio de uma iterao
qualquer. Seja k um ndice com as propriedades asseguradas por ii. Se y 1 ento
o invariante vale no incio da prxima iterao com o mesmo k da iterao corrente,
quer A[m] seja igual a x, quer seja diferente. Suponha agora que y = 0. Como o
nmero de ocorrncias de x em A[k . . m] exatamente 12 (m k), o vetor A[k . . m] no
tem valor majoritrio. Como A[1 . . k1] tambm no tem valor majoritrio, A[1 . . m]
no tem valor majoritrio. Assim, no incio da prxima iterao, o invariante ii valer
com k = m 1.
Na ltima passagem pela linha 3 temos m = n + 1 e portanto existe k no intervalo
1 . . n tal que A[1 . . k1] no tem valor majoritrio e x ocorre exatamente 21 (nk +1+y)
vezes em A[k . . n]. Suponha agora que A[1 . . n] tem um valor majoritrio a. Como
A[1 . . k1] no tem valor majoritrio, a majoritrio em A[k . . n]. Portanto, a = x e
y 1. Conclumos assim que, no comeo da linha 10,
x um bom candidato.
As linhas 10 a 13 verificam se x de fato majoritrio.
Consumo de tempo. razovel supor que o consumo de tempo de uma execuo de qualquer das linhas do algoritmo constante, ou seja, no depende de n. Assim,
podemos estimar o consumo de tempo total contando o nmero de execues das diversas linhas.
O bloco de linhas 4-9 executado n 1 vezes. O bloco de linhas 12-13 executado
n vezes. As linhas 1 e 2 e o bloco de linhas 14-16 executado uma s vez. Portanto, o
consumo de tempo total do algoritmo est em
(n)
(tanto no melhor quanto no pior caso). O algoritmo linear.

36

FEOFILOFF

Como se v, a anlise do consumo de tempo do algoritmo muito simples. A


dificuldade do problema est em inventar um algoritmo que seja mais rpido que o
algoritmo bvio.

Notas bibliogrficas
Este captulo foi baseado nos livros de Bentley [1] e Manber [14].

Captulo 7

Multiplicao de nmeros naturais


Quanto tempo necessrio para multiplicar dois nmeros naturais? Se os nmeros tm
m e n dgitos respectivamente, o algoritmo usual consome tempo proporcional a mn.
No caso m = n, o consumo de tempo , portanto, proporcional a n2 .
difcil imaginar um algoritmo mais rpido que o usual se m e n forem pequenos
(menores que duas ou trs centenas, digamos). Mas existe um algoritmo que bem
mais rpido quando m e n so grandes (como acontece em criptografia, por exemplo).

7.1

O problema

Usaremos notao decimal para representar nmeros naturais. (Poderamos igualmente bem usar notao binria, ou notao base 232 , por exemplo.) Diremos que um
dgito qualquer nmero menor que 10. Diremos que um nmero natural u tem n
dgitos1 se u < 10n . Com esta conveno, podemos nos restringir, sem perder generalidade, ao caso em que os dois multiplicandos tm o mesmo nmero de dgitos:
Problema da Multiplicao: Dados nmeros naturais u e v com n dgitos cada,
calcular o produto u v.
Voc deve imaginar que cada nmero natural representado por um vetor de dgitos. Mas nossa discusso ser conduzida num nvel de abstrao alto, sem manipulao
explcita desse vetor. (Veja a Seo 7.5.)

7.2

O algoritmo usual

Preliminarmente, considere a operao de adio. Sejam u e v dois nmeros naturais


com n dgitos cada. A soma u+v tem n+1 dgitos e o algoritmo usual de adio calcula
u + v em tempo proporcional a n.
Considere agora o algoritmo usual de multiplicao de dois nmeros u e v com n
1

Teria sido melhor dizer tem no mximo n dgitos.

37

38

FEOFILOFF

dgitos cada. O algoritmo tem dois passos. O primeiro passo calcula todos os n produtos de u por um dgito de v (cada um desses produtos tem n + 1 dgitos). O segundo
passo do algoritmo desloca para a esquerda, de um nmero apropriado de casas, cada
um dos n produtos obtidos no primeiro passo e soma os n nmeros resultantes. O
produto u v tem 2n dgitos.
O primeiro passo do algoritmo consome tempo proporcional a n2 . O segundo passo
tambm consome tempo proporcional a n2 . Assim, o consumo de tempo do algoritmo
usual de multiplicao est em (n2 ).
9999
7777

A
B

69993
69993
69993
69993

C
D
E
F

77762223

Figura 7.1: Algoritmo usual de multiplicao de dois nmeros naturais. Aqui estamos multiplicando 9999 por 7777 para obter o produto 77762223. A linha C o
resultado da multiplicao da linha A pelo dgito menos significativo da linha B. As
linhas D, E e F so definidas de maneira semelhante. A linha G o resultado da soma
das linhas C a F.

Exerccio
7.1 Descreva o algoritmo usual de adio em pseudocdigo. O algoritmo deve receber nmeros u e v com n dgitos cada e devolver a soma u + v.
7.2 Descreva algoritmo usual de multiplicao em pseudocdigo. O algoritmo deve receber
nmeros u e v com n dgitos cada e devolver o produto u v.

7.3

Diviso e conquista

Sejam u e v dois nmeros com n dgitos cada. Suponha, por enquanto, que n par. Seja
p o nmero formado pelos n/2 primeiros dgitos de u e seja q o nmero formado pelos
n/2 ltimos dgitos de u. Assim,
u = p 10n/2 + q .
Defina r e s analogamente para v, de modo que v = r 10n/2 + s. Teremos ento
u v = p r 10n + (p s + q r) 10n/2 + q s .

(7.1)

Esta expresso reduz a multiplicao de dois nmeros com n dgitos cada a quatro
multiplicaes (a saber, p por r, p por s, q por r e q por s) de nmeros com n/2 dgitos

ANLISE DE ALGORITMOS

39

cada.2
Se n for uma potncia de 2, o truque pode ser aplicado recursivamente a cada uma
das quatro multiplicaes menores. O resultado o seguinte algoritmo recursivo, que
recebe nmeros naturais u e v com n dgitos cada e devolve o produto u v:
R ASCUNHO (u, v, n)
1 se n = 1
2
ento devolva u v
3
seno m n/2
4
p bu/10m c
5
q u mod 10m
6
r bv/10m c
7
s v mod 10m
8
pr R ASCUNHO (p, r, m)
9
qs R ASCUNHO (q, s, m)
10
ps R ASCUNHO (p, s, m)
11
qr R ASCUNHO (q, r, m)
12
x pr 102m + (ps + qr ) 10m + qs
13
devolva x
O algoritmo est correto. claro que o algoritmo produz o resultado correto
se n = 1. Suponha agora que n 2. Como m < n, podemos supor, por hiptese
de induo, que a linha 8 produz o resultado correto, ou seja, que pr = p r. Analogamente, podemos supor que qs = q s, ps = p s e qr = q r no incio da linha 12. A
linha 12 no faz mais que implementar (7.1). Portanto, x = u v.
Consumo de tempo. As linhas 4 a 7 envolvem apenas o deslocamento de casas
decimais, podendo portanto ser executadas em no mais que n unidades de tempo. As
multiplicaes por 102m e 10m na linha 12 tambm consomem no mximo n unidades
de tempo, pois podem ser executadas com um mero deslocamento de casas decimais.
As adies na linha 12 consomem tempo proporcional ao nmero de dgitos de x, igual
a 2n.
Portanto, se denotarmos por T (n) o consumo de tempo do algoritmo no pior caso,
teremos
T (n) = 4 T (n/2) + n .
(7.2)
As quatro parcelas T (n/2) se referem s linhas 8 a 11 e a parcela n se refere ao consumo
das demais linhas. Segue da que T est em (n2 ), como j vimos no Exerccio 3.9.
Assim, o algoritmo R ASCUNHO no mais eficiente que o algoritmo usual de multiplicao.
2

Minha calculadora de bolso no capaz de exibir/armazenar nmeros que tenham mais que n dgitos. Para calcular o produto de dois nmeros com n dgitos cada, posso recorrer equao (7.1): uso a
mquina para calcular os quatro produtos e depois uso lpis e papel para fazer as trs adies.

40

FEOFILOFF

99998888
77776666

u
v

9999

p
q
r
s

8888
7777
6666
77762223
59247408
135775310

pr
qs
ps + qr

7777580112347408

Figura 7.2: Multiplicao de u por v calculada pelo algoritmo R ASCUNHO. Neste


exemplo temos n = 8. O resultado da operao x.

7.4

Algoritmo de Karatsuba

Para tornar o algoritmo da seo anterior muito mais rpido, basta observar que os trs
nmeros de que precisamos do lado direito de (7.1) a saber, p r, (p s + q r) e q s
podem ser obtidos com apenas trs multiplicaes. De fato,
ps+qr = yprqs,
sendo y = (p + q) (r + s). Assim, a equao (7.1) pode ser substituda por
u v = p r 10n + (y p r q s) 10n/2 + q s .

(7.3)

( bem verdade que (7.3) envolve duas adies e duas subtraes adicionais, mas essas
operaes consomem muito menos tempo que as multiplicaes.) Se n no par, basta
trocar n/2 por dn/2e: teremos u = p 10dn/2e + q e v = r 10dn/2e + s e portanto
u v = p r 102dn/2e + (y p r q s) 10dn/2e + q s .
Segue da o seguinte algoritmo de Karatsuba, que recebe nmeros naturais u e v com
n dgitos cada e devolve o produto u v:
K ARATSUBA (u, v, n)
1 se n 3
2
ento devolva u v
3
seno m dn/2e
4
p bu/10m c
5
q u mod 10m
6
r bv/10m c
7
s v mod 10m
8
pr K ARATSUBA (p, r, m)
9
qs K ARATSUBA (q, s, m)
10
y K ARATSUBA (p + q, r + s, m+1)
11
x pr 102m + (y pr qs) 10m + qs
12
devolva x

41

ANLISE DE ALGORITMOS

O algoritmo est correto. A prova da correo do algoritmo anloga prova


da correo do algoritmo R ASCUNHO. As instncias em que n vale 1, 2 ou 3 devem ser
tratadas na base da recurso porque o algoritmo aplicado, na linha 10, a uma instncia
de tamanho dn/2e + 1, e este nmero s menor que n quando n > 3.
Consumo de tempo.
no pior caso. Ento

Seja T (n) o consumo de tempo do algoritmo K ARATSUBA

T (n) = 2 T (dn/2e) + T (dn/2e + 1) + n .

(7.4)

As duas parcelas T (dn/2e) e a parcela T (dn/2e + 1) se referem s linhas 8, 9 e 10 respectivamente. A parcela n representa o consumo de tempo das demais linhas.
Como sugerimos na Seo 3.5, a funo T est na mesma classe assinttica que a
funo T 0 que satisfaz a recorrncia T 0 (n) = 3T 0 (bn/2c) + n. De acordo com a Seo 3.4,
T 0 est em (nlg 3 ). Portanto
T est em (nlg 3 ) .
(7.5)
Como lg 3 < 1.6, o algoritmo K ARATSUBA mais rpido que o algoritmo usual. (Ob
serve que nlg 3 apenas um pouco maior que n n.) Mas, em virtude da constante
multiplicativa escondida sob a notao , esta superioridade s se manifesta quando
n maior que algumas centenas.
999988888
077766666

u
v

5925807408

pr
qs

07769223
98887
67443
6669235941
735659310
077765801856807408

p+q
r+s
y
y pr qs
x

Figura 7.3: Multiplicao de u por v calculada pelo algoritmo K ARATSUBA. O resultado da operao x. Se u e v tivessem n dgitos cada, pr e qs teriam n + 1 dgitos cada,
y teria n + 2 (mais precisamente, s n + 1) dgitos e x teria 2n dgitos.

7.5

Detalhes de implementao

Para implementar os algoritmos que discutimos acima, preciso representar cada nmero por um vetor de dgitos, ou seja, um vetor U [1 . . n] cujos componentes pertencem
ao conjunto {0, 1, . . . , 9}. Um tal vetor representa o nmero natural U [n] 10n1 +
U [n1] 10n2 + + U [2] 10 + U [1].
O algoritmo K ARATSUBA recebe os vetores U [1 . . n] e V [1 . . n] que representam u e
v respectivamente e devolve o vetor X[1 . . 2n] que representa x. Nas linhas 4 e 5, p
representado por U [m+1 . . n] e q representado por U [1 . . m]. A implementao das

42

FEOFILOFF

Figura 7.4: Vetor U [1 . . 9] que representa o nmero 999988888.


linhas 6 e 7 anloga. Nas linhas 8 e 9, pr representado por um vetor PR[1 . . 2m] e qs
representado por um vetor QS [1 . . 2m].
Na linha 10, para calcular p + q basta submeter U [m+1 . . n] e U [1 . . m] ao algoritmo usual de adio, que produz um vetor A[1 . . m+1]. Algo anlogo vale para a
subexpresso r + s. O nmero y representado por um vetor Y [1 . . 2m+1].
Na linha 11, o valor de y pr qs calculado pelo algoritmo usual de subtrao
(no preciso cuidar de nmeros negativos pois y pr qs 0). Para calcular o
valor da expresso pr 102m + (y pr qs) 10m + qs, basta concatenar os vetores
PR[1 . . 2m] e QS [1 . . 2m] que representam pr e qs respectivamente e somar o resultado
com y pr qs (deslocado de m posies) usando o algoritmo usual de adio.

7.6

Diviso e conquista

O algoritmo K ARATSUBA um bom exemplo de aplicao da estratgia de diviso e


conquista, que j encontramos nos Captulos 4 e 5. O segredo do sucesso da estratgia
neste caso est no fato de que o processo de diviso da instncia original (linhas 3 a 7 do
algoritmo) e o processo de combinao das solues das instncias menores (linha 11)
consomem relativamente pouco tempo.

Notas bibliogrficas
Este captulo foi baseada na Seo 7.1 do livro de Brassard e Bratley [2]. O assunto
tambm discutido nos livros de Knuth [11], Dasgupta, Papadimitriou e Vazirani [4] e
Kleinberg e Tardos [10].
O algoritmo K ARATSUBA foi publicado em 1962 pelos matemticos russos Anatolii
Karatsuba e Yurii Ofman. Veja o verbetes Multiplication algorithm e Karatsuba algorithm
na Wikipedia.

Captulo 8

Escalonamento de intervalos
Imagine que vrios eventos querem usar um certo centro de convenes. Cada evento
gostaria de usar o centro durante o intervalo de tempo que comea numa data a e
termina numa data b. Dois eventos so considerados compatveis se os seus intervalos
de tempo so disjuntos. Cada evento tem um certo valor e a administrao do centro
precisa selecionar um conjunto de eventos mutuamente compatveis que tenha o maior
valor total possvel.

8.1

O problema

Sejam a1 , a2 , . . . , an e b1 , b2 , . . . , bn nmeros naturais tais que ai bi para cada i.


Cada ndice i representa o intervalo que tem origem ai e trmino bi , ou seja, o conjunto
{ai , ai +1, . . . , bi 1, bi }.
Dois intervalos distintos i e j so compatveis se bi < aj ou bj < ai . Um conjunto
de intervalos vivel se seus elementos so compatveis dois a dois.
A cada intervalo i est associado um nmero natural vi que representa P
o valor
do intervalo. O valor de um conjunto S de intervalos o nmero v(S) :=
iS vi .
0
Um conjunto vivel S tem valor mximo se v(S) v(S ) para todo conjunto S 0 de
intervalos que seja vivel.
Problema dos Intervalos Compatveis de Valor Mximo: Dados nmeros naturais a1 , . . . , an , b1 , . . . , bn e v1 , . . . , vn tais que ai bi para cada i, encontrar um
subconjunto vivel de {1, . . . , n} que tenha valor mximo.
A primeira ideia que vem mente a de um algoritmo guloso1 que escolhe os
intervalos em ordem decrescente de valor. Mas isso no resolve o problema.
1

Um algoritmo guloso constri uma soluo escolhendo, a cada passo, o objeto mais saboroso de
acordo com algum critrio estabelecido a priori.

43

44

FEOFILOFF

Exerccio
8.1 Coloque os intervalos em ordem decrescente de valor, ou seja, suponha que v1 v2
vn . Agora considere o seguinte algoritmo. A m-sima iterao do algoritmo comea
com um subconjunto vivel S de {1, . . . , m1}. Se S {m} for vivel, comece nova iterao
com S {m} no lugar de S. Seno, comece nova iterao sem alterar S. Mostre que este
algoritmo guloso. no resolve o problema.

8.2

A estrutura recursiva do problema

Adote a abreviatura svvm para a expresso subconjunto vivel de valor mximo


e seja S um svvm do conjunto de intervalos {1, . . . , n}. Se S no contm n ento S
tambm um svvm de {1, . . . , n 1}. Se S contm n ento S {n} um svvm do
conjunto de todos os intervalos que so compatveis com n.
Podemos resumir esta propriedade dizendo que o problema tem estrutura recursiva: qualquer soluo de uma instncia do problema contm solues de instncias
menores.
Para simplificar a descrio do conjunto de intervalos compatveis com n, convm
supor que os intervalos esto em ordem crescente de trminos, ou seja, que
b1 b2 bn .

(8.1)

Sob esta hiptese, o conjunto dos intervalos compatveis com n simplesmente


{1, . . . , j}, sendo j o maior ndice tal que bj < an .
Se denotarmos por X(n) o valor de um svvm de {1, . . . , n}, a estrutura recursiva
do problema garante que

X(n) = max X(n 1) , X(j) + vn ,
(8.2)
sendo j o maior ndice tal que bj < an . Se tal j no existe ento (8.2) se reduz a

X(n) = max X(n 1) , vn .
Esta recorrncia pode ser facilmente transformada em um algoritmo recursivo. Mas o
algoritmo muito ineficiente, pois resolve cada subinstncia repetidas vezes.

Exerccio
8.2 Escreva um algoritmo recursivo baseado em (8.2). Mostre que o consumo de tempo do
algoritmo no pior caso est em (2n ). (Sugesto: Considere um conjunto com n intervalos
compatveis dois a dois, todos com valor 1. Mostre que o tempo T (n) que o algoritmo
consome para processar o conjunto satisfaz a recorrncia T (n) = T (n 1) + T (n 1) + 1.)

8.3

Algoritmo de programao dinmica

Para tirar bom proveito da recorrncia (8.2), preciso recorrer tcnica da programao
dinmica (veja a Seo 5.5), que consiste em guardar as solues das subinstncias

ANLISE DE ALGORITMOS

45

numa tabela medida que elas forem sendo resolvidas. Com isso, cada subinstncia
ser resolvida uma s vez.
O seguinte algoritmo recebe n intervalos que satisfazem (8.1) e devolve o valor de
um svvm de {1, . . . , n}:
I NTERVALOS C OMPATVEIS (a1 , . . . , an , b1 , . . . , bn , v1 , . . . , vn )
1 X[0] 0
2 para m 1 at n faa
3
j m1
4
enquanto j 1 e bj am faa
5
j j1
6
se X[m 1] > X[j] + vm
7
ento X[m] X[m 1]
8
seno X[m] X[j] + vm
9 devolva X[n]
(No difcil extrair da tabela X um svvm de {1, . . . , n}.)
O algoritmo est correto. Na linha 2, imediatamente antes da comparao de m
com n,
X[m1] o valor de um svvm de {1, . . . , m1},
X[m2] o valor de um svvm de {1, . . . , m2}, . . . ,
X[1] o valor de um svvm de {1}.
Este invariante certamente vale no incio da primeira iterao, quando m = 1. Suponha agora que ele vale no incio de uma iterao qualquer. Para mostrar que continua
valendo no incio da iterao seguinte, observe que, no comeo da linha 6, {1, . . . , j}
o conjunto dos intervalos compatveis com m. Assim, o valor atribudo a X[m] nas
linhas 7 e 8 est de acordo com a recorrncia (8.2) e portanto X[m] o valor de um
svvm de {1, . . . , m}.
Na ltima passagem pela linha 2 temos m = n + 1 e portanto X[n] o valor de um
svvm de {1, . . . , n}. Assim, o algoritmo cumpre o que prometeu.
Consumo de tempo. Uma execuo de qualquer linha do algoritmo I NTERVA LOS C OMPATVEIS consome uma quantidade de tempo que no depende de n. Logo, o
consumo de tempo total do algoritmo pode ser medido contando o nmero de execues das diversas linhas.
Para cada valor
5 executada no mximo m 1 vezes. Como m
Pn fixo de m, a linha
1
2
varia de 1 a n e m=1 (m 1) = 2 (n n), a linha 5 executada menos que n2 vezes.
Todas as demais linhas so executadas no mximo n 1 vezes. Logo, o consumo de
tempo total do algoritmo est em
O(n2 )
no pior caso. Uma anlise um pouco mais cuidadosa mostra que o consumo est em
(n2 ) no pior caso.

46

FEOFILOFF

No levamos em conta ainda o pr-processamento que rearranja os intervalos em


ordem crescente de trmino. Como esse pr-processamento pode ser feito em tempo
O(n lg n) (veja o Captulo 4) e n lg n est em O(n2 ), o consumo de tempo total (n2 ).
(Mas veja o Exerccio 8.3.)

Exerccios
8.3 Mostre que o algoritmo I NTERVALOS C OMPATVEIS pode ser implementado de modo a consumir apenas O(n) unidades de tempo. Sugesto: construa uma tabela auxiliar que produza, em tempo constante, efeito equivalente ao das linhas 4-5.
8.4 Escreva um algoritmo de ps-processamento que extraia da tabela X[1 . . n] produzida pelo
algoritmo I NTERVALOS C OMPATVEIS um svvm de {1, . . . , n}. O seu algoritmo deve consumir O(n) unidades de tempo.

Notas bibliogrficas
O problema dos intervalos valorados discutido no livro de Kleinberg e Tardos [10]. O
verbete Interval scheduling na Wikipedia trata do escalonamento de intervalos.

Captulo 9

As linhas de um pargrafo
Um pargrafo de texto uma sequncia de palavras, sendo cada palavra uma sequncia de caracteres. Queremos imprimir um pargrafo em uma ou mais linhas consecutivas de uma folha de papel de tal modo que cada linha tenha no mximo L caracteres.
As palavras do pargrafo no devem ser quebradas entre linhas e cada duas palavras
consecutivas numa linha devem ser separadas por um espao.
Para que a margem direita fique razoavelmente uniforme, queremos distribuir as
palavras pelas linhas de modo a minimizar a soma dos cubos dos espaos em branco
que sobram no fim de todas as linhas exceto a ltima.

9.1

O problema

Para simplificar a discusso do problema, convm numerar as palavras do pargrafo


em ordem inversa e confundir as palavras com os seus comprimentos. Diremos, pois,
que um pargrafo uma sequncia cn , cn1 , . . . , c2 , c1 de nmeros naturais. Diremos
tambm que cada ci uma palavra: cn a primeira palavra do pargrafo e c1 a ltima.
Um trecho de um pargrafo cn , cn1 , . . . , c1 qualquer sequncia da forma
cm , cm1 , . . . , ck com n m k 1. Este trecho ser denotado por (m, k). O comprimento do trecho (m, k) o nmero
c(m, k) := cm + 1 + cm1 + 1 + + 1 + ck .
Os prximos conceitos envolvem um nmero natural L que chamaremos capacidade
de uma linha. Um trecho (m, k) curto se c(m, k) L. O defeito de um trecho curto
(m, k) o nmero
(L c(m, k))3 .
Uma L-decomposio do pargrafo cn , cn1 , . . . , c1 uma subdiviso do pargrafo em
trechos curtos. Mais precisamente, uma L-decomposio uma sequncia
(n, kq ), (kq 1, kq1 ), (kq1 1, kq2 ), . . . , (k2 1, k1 ) (k1 1, 1)
de trechos curtos em que n kq > kq1 > > k2 > k1 > 1. O defeito de uma
decomposio a soma dos defeitos de todos os trechos da decomposio exceto o
ltimo. Uma decomposio tima se tem defeito mnimo.
47

48

FEOFILOFF

Aaaa bb cccc d eee ff gggg iii


jj kkk. Llll mmm nn ooooo----ppppp qq r sss ttt uu.
Aaaa bb cccc d eee ff gggg---iii jj kkk. Llll mmm nn oooooppppp qq r sss ttt uu.

Figura 9.1: Duas decomposies do mesmo pargrafo. As linhas tm capacidade L = 30 e os caracteres - representam os espaos em branco que contribuem para o defeito. O defeito da primeira decomposio 03 + 53 = 125 e o da
segunda 43 + 13 = 65.

ccc

bbb ccc

aaa bbb-ccc

Figura 9.2: direita temos uma decomposio tima de um pargrafo c3 , c2 , c1 . A


capacidade das linhas L = 9. Os caracteres - representam os espaos em branco
que contribuem para o defeito. No centro, temos uma decomposio tima do pargrafo c2 , c1 . esquerda, uma decomposio tima do pargrafo c1 .

Problema da Decomposio de um Pargrafo: Dado um pargrafo cn , cn1 , . . . ,


c1 e um nmero natural L, encontrar uma L-decomposio tima do pargrafo.
claro que as instncias do problema em que ci > L para algum i no tm soluo.

Exerccios
9.1 Tente explicar por que a definio de defeito usa a terceira potncia e no a primeira ou a
segunda.
9.2 Considere a seguinte heurstica gulosa: preencha a primeira linha at onde for possvel,
depois preencha o mximo possvel da segunda linha, e assim por diante. Mostre que esta
heurstica no resolve o problema.
9.3 Suponha que ci = 1 para i = n, . . . , 1. Mostre que o defeito de uma decomposio tima
no mximo b2n/Lc.

9.2

A estrutura recursiva do problema

O problema da decomposio de pargrafos tem carter recursivo, como passamos


a mostrar. Suponha que (n, k) o primeiro trecho de uma decomposio tima do

49

ANLISE DE ALGORITMOS

pargrafo cn , cn1 , . . . , c1 . Se k 2 ento


a correspondente decomposio de ck1 , ck2 , . . . , c1 tima.
Eis a prova desta propriedade: Seja x o defeito da decomposio de ck1 , . . . , c1 induzida pela decomposio tima de cn , . . . , c1 . Suponha agora, por um momento, que o
pargrafo ck1 , . . . , c1 tem uma decomposio com defeito menor que x. Ento a combinao desta decomposio com o trecho (n, k) uma decomposio de cn , . . . , c1 que
tem defeito menor que o mnimo, o que impossvel.
A propriedade recursiva pode ser representada por uma relao de recorrncia.
Seja X(n) o defeito de uma decomposio tima do pargrafo cn , cn1 , . . . , c1 . Se o
trecho (n, 1) curto ento X(n) = 0. Caso contrrio,

(L c(n, k))3 + X(k1) ,
(9.1)
X(n) = min
c(n,k)L

sendo o mnimo tomado sobre todos os trechos curtos da forma (n, k).
A recorrncia poderia ser transformada facilmente num algoritmo recursivo. Mas
o clculo do min em (9.1) levaria o algoritmo a resolver as mesmas subinstncias vrias
vezes, o que muito ineficiente.

9.3

Um algoritmo de programao dinmica

Para usar a recorrncia (9.1) de maneira eficiente, basta interpretar X como uma tabela X[1 . . n] e calcular X[n], depois X[n1], e assim por diante. Esta a tcnica da
programao dinmica. O seguinte algoritmo implementa esta ideia. Ele devolve o defeito mnimo de um pargrafo cn , cn1 , . . . , c1 supondo n 1, linhas de capacidade L
e ci L para todo i:
D EFEITO M NIMO (cn , . . . , c1 , L)
1 para m 1 at n faa
2
X[m]
3
km
4
s cm
5
enquanto k > 1 e s L faa
6
X 0 (L s)3 + X[k1]
7
se X 0 < X[m] ento X[m] X 0
8
k k1
9
s s + 1 + ck
10
se s L ento X[m] 0
11 devolva X[n]
(No difcil modificar o algoritmo de modo que ele produza uma decomposio
tima e no apenas o seu defeito.)
No incio de cada iterao do bloco de linhas 6-9, o valor da varivel s c(m, k). As
primeiras execues do processo iterativo descrito nas linhas 5-9 terminam tipicamente

50

FEOFILOFF

com k = 1 e (m, k) o nico trecho da decomposio. As execues subsequentes do


mesmo bloco terminam com k 2 e portanto com s > L.
O algoritmo est correto. Na linha 1, imediatamente antes da comparao de m
com n, temos o seguinte invariante:
X[m 1] o defeito mnimo do pargrafo cm1 , . . . , c1 ,
X[m 2] o defeito mnimo do pargrafo cm2 , . . . , c1 ,
... ,
X[1] o defeito mnimo do pargrafo c1 .
Este invariante vale vacuamente na primeira passagem pela linha 1. Suponha agora
que o invariante vale no incio de uma iterao qualquer. A propriedade continua
valendo no incio da iterao seguinte, pois o bloco de linhas 2-10 calcula o defeito de
uma decomposio tima de pargrafo cm , cm1 , . . . , c1 usando a recorrncia (9.1).
No fim do processo iterativo temos m = n + 1 e portanto X[n] o defeito mnimo
do pargrafo cn , . . . , c1 .
Consumo de tempo. Adote n como tamanho da instncia (cn , . . . , c1 , L) do problema. Podemos supor que uma execuo de qualquer linha do cdigo consome uma
quantidade de tempo que no depende de n. Assim, o consumo de tempo determinado pelo nmero de execues das vrias linhas.
Para cada valor fixo de m, o bloco de linhas 6-9 executado no mximo m 1
vezes. Como m assume os valores 1, 2, . . . , n, o nmero total de execues do bloco de
linhas 6-9 no passa de 21 n(n 1). Portanto, o algoritmo consome
(n2 )
unidades de tempo no pior caso. No melhor caso (que acontece, por exemplo, quando
ci dL/2e para cada i), o algoritmo consome (n) unidades de tempo.

Exerccio
9.4 Modifique o algoritmo D EFEITO M NIMO para que ele devolva a descrio hkq , kq1 , . . . , k1 i
de uma decomposio tima do pargrafo cn , . . . , c1 e no apenas o defeito da decomposio.

Notas bibliogrficas
O problema que discutimos neste captulo proposto como exerccio nos livros de Cormen et al. [3], Parberry [17] e Parberry e Gasarch [18].

Captulo 10

Mochila de valor mximo


Suponha dado um conjunto de objetos e uma mochila. Cada objeto tem um certo peso
e um certo valor. Queremos escolher um conjunto de objetos que tenha o maior valor
possvel sem ultrapassar a capacidade (ou seja, o limite de peso) da mochila. Este
clebre problema aparece em muitos contextos e faz parte de muitos problemas mais
elaborados.

10.1

O problema

Suponha dados nmeros naturais p1 , . . . , pn e v1 , . . . , vn . Diremos que pi o peso e vi o


valor
de i.P
Para qualquer subconjunto S de {1, 2, . . . , n}, sejam p(S) e v(S) os nmeros
P
iS vi respectivamente. Diremos que p(S) o peso e v(S) o valor de S.
iS pi e
Em relao a um nmero natural c, um subconjunto S de {1, . . . , n} vivel se
p(S) c. Um subconjunto vivel S de {1, . . . , n} timo se v(S ) v(S) para todo
conjunto vivel S.
Problema da Mochila: Dados nmeros naturais p1 , . . . , pn , c, v1 , . . . , vn , encontrar um subconjunto timo de {1, . . . , n}.
Uma soluo da instncia (n, p, c, v) do problema qualquer subconjunto timo
de {1, . . . , n}. Poderamos ser tentados a encontrar uma soluo examinando todos os
subconjuntos {1, . . . , n}. Mas esse algoritmo invivel, pois consome tempo (2n ).

10.2

A estrutura recursiva do problema

Seja S uma soluo da instncia (n, p, c, v). Temos duas possibilidades, conforme n
esteja ou no em S. Se n
/ S ento S tambm um soluo da instncia (n 1, p, c, v).
Se n S ento S {n} soluo de (n 1, p, c pn , v).
Podemos resumir isso dizendo que o problema tem estrutura recursiva: toda soluo de uma instncia do problema contm solues de instncias menores.
Se denotarmos por X(n, c) o valor de um soluo de (n, p, c, v), a estrutura recur51

52

FEOFILOFF

siva do problema pode ser representada pela seguinte recorrncia:



X(n, c) = max X(n 1, c) , X(n 1, c pn ) + vn .

(10.1)

O segundo termo de max s faz sentido se c pn 0, e portanto


X(n, c) = X(n 1, c)

(10.2)

quando pn > c.
Poderamos calcular X(n, c) recursivamente. Mas o algoritmo resultante muito
ineficiente, pois resolve cada subinstncia um grande nmero de vezes.

Exerccio
10.1 Escreva um algoritmo recursivo baseado na recorrncia (10.1-10.2). Calcule o consumo de
tempo do seu algoritmo no pior caso. (Sugesto: para cada n, tome a instncia em que
c = n e pi = vi = 1 para cada i. Mostre que o consumo de tempo T (n) para essa famlia de
instncias satisfaz a recorrncia T (n) = 2T (n 1) + 1.)

10.3

Algoritmo de programao dinmica

Para obter um algoritmo eficiente a partir da recorrncia (10.1-10.2), preciso armazenar as solues das subinstncias numa tabela medida que elas forem sendo obtidas,
evitando assim que elas sejam recalculadas. Esta a tcnica da programao dinmica,
que j encontramos em captulos anteriores.
Como c e todos os pi so nmeros naturais, podemos tratar X como uma tabela
com linhas indexadas por 0 . . n e colunas indexadas por 0 . . c. Para cada i entre 0 e n
e cada b entre 0 e c, a casa X[i, b] da tabela ser o valor de uma soluo da instncia
(i, p, b, v). As casas da tabela X precisam ser preenchidas na ordem certa, de modo
que toda vez que uma casa for requisitada o seu valor j tenha sido calculado.
O algoritmo abaixo recebe uma instncia (n, p, c, v) do problema e devolve o valor
de uma soluo da instncia:1
M OCHILA PD (n, p, c, v)
1 para b 0 at c faa
2
X[0, b] 0
3
para j 1 at n faa
4
x X[j 1, b]
5
se b pj 0
6
ento y X[j 1, b pj ] + vj
7
se x < y ento x y
8
X[j, b] x
9 devolva X[n, c]
1
fcil extrair da tabela X um subconjunto vivel de {1, . . . , n} que tenha valor X[n, c]. Veja o Exerccio 10.4.

53

ANLISE DE ALGORITMOS

p
4
2
1
3

v
500
400
300
450

0
1
2
3
4

0
1
2
3
4
5
0
0
0
0
0
0
0
0
0
0 500 500
0
0 400 400 500 500
0 300 400 700 700 800
0 300 400 700 750 850

Figura 10.1: Uma instncia do Problema da Mochila com n = 4 e c = 5. A


figura mostra a tabela X[0 . . n, 0 . . c] calculada pelo algoritmo M OCHILA PD.

O algoritmo est correto. A cada passagem pela linha 1, imediatamente antes das
comparao de b com c, as b primeiras colunas da tabela esto corretas, ou seja,
X[i, a] o valor de uma soluo da instncia (i, p, a, v)

(10.3)

para todo i no intervalo 0 . . n e todo a no intervalo 0 . . b1. Para provar este invariante,
basta entender o processo iterativo nas linhas 3 a 8. No incio de cada iterao desse
processo,
X[i, b] o valor de uma soluo da instncia (i, p, b, v)
(10.4)
para todo i no intervalo 0 . . j1. Se o invariante (10.4) vale no incio de uma iterao,
ele continua valendo no incio da iterao seguinte em virtude da recorrncia (10.110.2). Isto prova que (10.3) de fato vale a cada passagem pela linha 1.
Na ltima passagem pela linha 1 temos b = c + 1 e portanto (10.3) garante que
X[n, c] o valor de uma soluo da instncia (n, p, c, v).
Consumo de tempo. razovel supor que uma execuo de qualquer das linhas
do cdigo consome uma quantidade de tempo que no depende de n nem de c. Portanto, basta contar o nmero de execues das diversas linhas.
Para cada valor fixo de b, o bloco de linhas 4-8 executado n vezes. Como b varia
de 0 a c, o nmero total de execues do bloco de linhas 4-8 (c + 1)n. As demais linhas
so executadas no mximo c + 1 vezes. Esta discusso mostra que o algoritmo consome
(nc)
unidades de tempo. (Poderamos ter chegado mesma concluso observando que o
consumo de tempo do algoritmo proporcional ao nmero de casas da tabela X.)
O consumo de tempo de M OCHILA PD muito sensvel s variaes de c. Imagine, por exemplo, que c e os elementos de p so todos multiplicados por 100. Como
isto constitui uma mera mudana de escala, a nova instncia do problema conceitualmente idntica original. No entanto, nosso algoritmo consumir 100 vezes mais
tempo para resolver a nova instncia.

54

FEOFILOFF

Observaes sobre o consumo de tempo. Ao dizer que o consumo de tempo do


algoritmo (nc), estamos implicitamente adotando o par de nmeros (n, c) como
tamanho da instncia (n, p, c, v). No entanto, mais razovel dizer que o tamanho da
instncia (n, dlg ce), pois c pode ser escrito com apenas dlg ce bits. mais razovel,
portanto, dizer que o algoritmo consome
(n2lg c )
unidades de tempo. Isto torna claro que o consumo de tempo cresce explosivamente
com lg c.
Gostaramos de ter um algoritmo cujo consumo de tempo no dependesse do valor
de c, um algoritmo cujo consumo de tempo estivesse em O(n2 ), ou O(n10 ), ou O(n100 ).
(Um tal algoritmo seria considerado fortemente polinomial.) Acredita-se, porm,
que um tal algoritmo no existe.2

Exerccios
10.2 verdade que X[i, 0] = 0 para todo i depois da execuo do algoritmo M OCHILA PD?
10.3 Por que nosso enunciado do problema inclui instncias em que c vale 0? Por que inclui
instncias com objetos de peso nulo?
10.4 Mostre como extrair da tabela X[0 . . n, 0 . . c] produzida pelo algoritmo M OCHILA PD um
subconjunto timo de {1, . . . , n}.
10.5 Faa uma mudana de escala para transformar o conjunto {0, 1, . . . , c} no conjunto de
nmeros racionais entre 0 e n. Aplique o mesmo fator de escala aos pesos pi . O algoritmo
M OCHILA PD pode ser aplicado a essa nova instncia do problema?

10.4

Instncias especiais do problema da mochila

Algumas colees de instncias do Problema da Mochila tm especial interesse prtico.


Se vi = pi para todo i, temos o clebre Problema Subset Sum, que pode ser apresentado
assim: imagine que voc emitiu cheques de valores v1 , . . . , vn durante o ms; se o banco
debitou um total de c na sua conta no fim do ms, quais podem ter sido os cheques
debitados?
Considere agora as instncias do Problema da Mochila em que vi = 1 para todo i.
(Voc pode imaginar que p1 , . . . , pn so os tamanhos de n arquivos digitais. Quantos
desses arquivos cabem num pen drive de capacidade c?) Esta coleo de instncias
pode ser resolvida por um algoritmo guloso bvio que muito mais eficiente que
M OCHILA PD.

Notas bibliogrficas
O problema da mochila discutido na Seo 16.2 do livro de Cormen et al. [3] e na
Seo 8.4 do livro de Brassard e Bratley [2], por exemplo.
2

O Problema da Mochila NP-difcil. Veja o livro de Cormen et al. [3].

Captulo 11

Mochila de valor quase mximo


O algoritmo de programao dinmica para o Problema da Mochila (veja o Captulo 10)
lento. Dada a dificuldade de encontrar um algoritmo mais rpido,1 faz sentido reduzir nossas exigncias e procurar por uma soluo quase tima. Um tal algoritmo
deve calcular um conjunto vivel de valor maior que uma frao predeterminada (digamos 50%) do valor mximo.

11.1

O problema

Convm repetir algumas das definies da Seo 10.1. Dados nmeros naturais
p1 , . . . , pn , c e v1 , . . . , vn , diremos que pi o peso e vi o P
valor de i. Para qualquer
subconjunto S de {1, . . . , n}, denotaremos por p(S) aP
soma iS pi e diremos que S
vivel se p(S) c. O valor de S o nmero v(S) := iS vi . Um conjunto vivel S
timo se v(S ) v(S) para todo conjunto vivel S.
Problema da Mochila: Dados nmeros naturais p1 , . . . , pn , c, v1 , . . . , vn , encontrar um subconjunto vivel timo de {1, . . . , n}.
Todo objeto de peso maior que c pode ser ignorado e qualquer objeto de peso nulo
pode ser includo em todos os conjuntos viveis. Suporemos ento, daqui em diante,
que
1 pi c
(11.1)
para todo i.

11.2

Algoritmo de aproximao

O algoritmo que descreveremos a seguir tem carter guloso e d preferncia aos objetos de maior valor especfico. O valor especfico de um objeto i o nmero vi /pi . Para
simplificar a descrio do algoritmo, suporemos que os objetos so dados em ordem
1

O problema NP-difcil. Veja o livro de Cormen et al. [3].

55

56

FEOFILOFF

decrescente de valor especfico, ou seja, que


v2
vn
v1


.
p1
p2
pn

(11.2)

Nosso algoritmo recebe uma instncia do problema que satisfaz as condies (11.1)
e (11.2) e devolve um subconjunto vivel X de {1, . . . , n} tal que
v(X) 12 v(S ) ,
sendo S um subconjunto vivel timo:
M OCHILA Q UASE TIMA (n, p, c, v)
1 X
2 sx0
3 k1
4 enquanto k n e s + pk c faa
5
X X {k}
6
s s + pk
7
x x + vk
8
k k+1
9 se k > n ou x vk
10
ento devolva X
11
seno devolva {k}
O bloco de linhas 4 a 8 determina o maior k tal que p1 + + pk1 c. No incio
da linha 9, X = {1, . . . , k1}, s = p(X) e x = v(X).
O algoritmo est correto. No incio da linha 9, claro que X vivel. Se k > n
ento X = {1, . . . , n} e o algoritmo adota X como soluo. Nesse caso, evidente que
v(X) 21 v(S) para todo conjunto vivel S, como prometido.
Suponha agora que k n no incio da linha 9. Graas hiptese (11.1), o conjunto
{k} vivel e o algoritmo adota como soluo o mais valioso dentre X e {k}. Resta
mostrar que
max (v(X), vk ) 12 v(S)
para todo conjunto vivel S. O primeiro passo da demonstrao consiste na seguinte
observao:
max (v(X), vk ) 12 (v(X) + vk ) = 12 v(R) ,
sendo R := X {k}. O segundo passo mostra que v(R) > v(S) qualquer que seja o

57

ANLISE DE ALGORITMOS

conjunto vivel S:
v(R) v(S) = v(R S) v(S R)
X
X
=
vi
vi
iRS

iRS

=
>
=

iSR

X vi
X vi
pi
pi
pi
pi
iSR

vk
vk
p(R S)
p(S R)
pk
pk

vk
p(R) p(S)
pk

vk
cc
pk
0.

(11.3)

(11.4)

A relao (11.3) vale porque vi /pi vk /pk para todo i em R e vi /pi vk /pk para todo i
no complemento de R. J (11.4) vale porque p(R) > c e p(S) c.
Consumo de tempo. Adote n (poderia igualmente ter adotado 2n + 1) como medida do tamanho da instncia (n, p, c, v) do problema. Uma execuo de qualquer
das linhas do algoritmo consome uma quantidade de tempo que no depende de n. O
bloco de linhas 5-8 executado no mximo n vezes. Assim, o algoritmo todo consome
(n)
unidades de tempo, tanto no pior quanto no melhor caso. O algoritmo propriamente
dito , portanto, linear.
O pr-processamento necessrio para fazer valer (11.1) e (11.2) pode ser feito em
tempo (n lg n) (veja o Captulo 4). Portanto, o consumo de tempo do processo todo
(n lg n) .

Exerccio
11.1 Construa uma instncia do Problema da Mochila para a qual o algoritmo devolve {k} na
linha 11.

11.3

Observaes sobre algoritmos de aproximao

Um algoritmo rpido cujo resultado uma frao predeterminadada soluo tima


conhecido como algoritmo de aproximao. O resultado do algoritmo M OCHILA Q UASE TIMA, por exemplo, melhor que 50% do timo. Esse fator de aproximao
pode parecer grosseiro, mas suficiente para algumas aplicaes que precisam de um
algoritmo muito rpido.

58

FEOFILOFF

Outros algoritmos de aproximao para o Problema da Mochila tm fator de aproximao bem melhor que 50%. O algoritmo de Ibarra e Kim (veja o livro de Fernandes et al. [8], por exemplo) garante um fator de aproximao to prximo de 100%
quanto o usurio desejar. Como seria de se esperar, o consumo de tempo do algoritmo
tanto maior quanto maior o fator de aproximao solicitado. O algoritmo de Ibarra e
Kim baseado numa variante de M OCHILA PD em que os papis de p e v so trocados.
(Veja o Exerccio 10.5.)

Notas bibliogrficas
Algoritmos de aproximao para o Problema da Mochila so discutidos na Seo 13.2
do livro de Brassard e Bratley [2].

Captulo 12

A cobertura de um grafo
Imagine um conjunto de salas interligadas por tneis. Um guarda postado numa sala
capaz de vigiar todos os tneis que convergem sobre a sala. Queremos determinar o
nmero mnimo de guardas suficiente para vigiar todos os tneis.
Se houver um custo associado com cada sala (este o custo de manter um guarda
na sala), queremos determinar o conjunto mais barato de guardas capaz de manter
todos os tneis sob vigilncia.

12.1

Grafos


Um grafo um par (V, A) de conjuntos tal que A V2 . Cada elemento de A , portanto, um par no ordenado de elementos de V . Os elementos de V so chamados
vrtices e os de A so chamados arestas.
Uma aresta {i, j} usualmente denotada por ij. Os vrtices i e j so as pontas
desta aresta.

12.2

O problema da cobertura

Uma cobertura de um grafo um conjunto X de vrtices que contm pelo menos uma
das pontas de cada aresta.
P Se cada vrtice i tem um custo ci , o custo de uma cobertura
X o nmero c(X) := iX ci .
Problema da Cobertura: Dado um grafo cujos vrtices tm custos em N, encontrar uma cobertura de custo mnimo.
Poderamos resolver o problema examinando todos os subconjuntos do conjunto
de vrtices, mas um tal algoritmo explosivamente lento: seu consumo de tempo
cresce exponencialmente com o nmero de vrtices. Infelizmente, acredita-se que
no existem algoritmos substancialmente mais rpidos para o problema, nem mesmo
quando todos os vrtices tm custo unitrio.1
1

O Problema da Cobertura NP-difcil. Veja o livro de Cormen et al. [3].

59

60

FEOFILOFF

Faz sentido, portanto, procurar por um bom algoritmo de aproximao, um algoritmo rpido que encontre uma cobertura cujo custo seja limitado por um mltiplo
predeterminado do timo. (Veja a Seo 11.3.)
r

r
r
r

r
r
r

r
r
r

Figura 12.1: Uma instncia do Problema da Cobertura. Encontre uma


cobertura mnima, supondo que todos os vrtices tm custo 1.

Exerccio
12.1 Seja (V, A) um grafo. Ignore os custos dos vrtices do grafo. Uma cobertura X desse grafo
mnima se no existe uma cobertura X 0 tal que |X 0 | < |X|. Uma cobertura X minimal
se no existe uma cobertura X 0 tal que X 0 X. Mostre que uma cobertura minimal pode
ser arbitrariamente maior que uma cobertura mnima.

12.3

Um algoritmo de aproximao

O seguinte algoritmo recebe um grafo (V, A) e um nmero natural ci para cada vrtice i
e devolve uma cobertura X tal que c(X) 2 c(X ), sendo X uma cobertura de custo
mnimo:
C OBERTURA B ARATA (V, A, c)
1 para cada i em V faa
2
xi 0
3 para cada ij em A faa
4
yij 0
5 para cada pq em A faa
6
e min (cp xp , cq xq )
7
ypq ypq + e
8
xp xp + e
9
xq xq + e
10 X
11 para cada i em V faa
12
se xi = ci ento X X {i}
13 devolva X
O algoritmo atribui nmeros naturais y s arestas. Voc pode imaginar que ypq
a quantia que a aresta pq paga a cada uma de suas pontas para convencer
Puma delas
a fazer parte da cobertura. Um vrtice p aceita participar da cobertura se q ypq cp ,
sendo a soma feita sobre todas as arestas
P que tm ponta p. A regra do jogo nunca
pagar mais que o necessrio. Portanto, q ypq cp para todo vrtice p.

61

ANLISE DE ALGORITMOS

O algoritmo est correto. No incio de cada iterao do bloco de linhas 6-9, temos
os seguintes invariantes:
P
i. xi = j yij para todo i em V ,
ii. xi ci para todo i em V ,
iii. para toda aresta ij j examinada tem-se xi = ci ou xj = cj .
Estas propriedades so obviamente verdadeiras no incio da primeira iterao. No
incio de cada iterao subsequente, o invariante i continua valendo, pois ypq , xp e xq
so acrescidos da mesma quantidade e. O invariante ii continua valendo, pois e
cp xp e e cq xq . O invariante iii continua valendo, pois e = cp xp ou e = cq xq .
Os invariantes i e ii tm a seguinte consequncia: no incio de cada iterao do
bloco de linhas 6-9, temos
X
yij c(Z)
(12.1)
ijA

P
para
qualquer
cobertura
Z.
Para
mostrar
isso,
basta
observar
que
ijA yij
P
P
P
P
iZ
j yij =
iZ xi
iZ ci . A primeira desigualdade vale porque toda aresta
tem pelo menos uma de suas pontas em Z. A igualdade seguinte vale em virtude do
invariante i. A ltima desigualdade decorre do invariante ii.
Agora observe que no fim do bloco de linhas 10-12 temos
X
c(X) 2
yij .
(12.2)
ijA

P
P
P
P
DePfato, como xi = ci para todo i em X, temos iX ci = iX xi = iX j yij
2 ijA yij . A segunda igualdade vale em virtude do invariante i. A ltima desigualdade verdadeira pois cada aresta tem no mximo duas pontas em X.
Segue de (12.2) e (12.1) que, depois do bloco de linhas 10-12, para qualquer cobertura Z,
c(X) 2 c(Z) .
Isto vale, em particular, se Z uma cobertura de custo mnimo. Como X uma cobertura (em virtude do invariante iii), o algoritmo cumpre o que prometeu.
O fator de aproximao 2 pode parecer ser grosseiro, mas o fato que ningum
descobriu ainda um algoritmo eficiente com fator de aproximao 1.9 por exemplo.
Consumo de tempo. Podemos supor que o grafo dado da maneira mais crua
possvel: os vrtices so 1, 2, . . . , n e as arestas so listadas em ordem arbitrria.
Seja m o nmero de arestas do grafo e adote o par (n, m) como tamanho de uma
instncia do problema. Podemos supor que uma execuo de qualquer das linhas do
algoritmo consome tempo que no depende de n nem de m. A linha 2 executada n
vezes. A linha 4 executada m vezes. A linha 12 executada n vezes. O bloco de
linhas 6-9 repetido m vezes. Assim, o consumo de tempo total do algoritmo est em
(n + m) ,
tanto no pior quanto no melhor caso. O algoritmo , portanto, linear.

62

12.4

FEOFILOFF

Comentrios sobre o mtodo primal-dual

O algoritmo C OBERTURA B ARATA o resultado da aplicao do mtodo primal-dual de


concepo de algoritmos. O primeiro passo do mtodo (omitido acima) escrever um
programa linear que represente o problema. As variveis duais do programa linear so
as variveis y do nosso algoritmo. A relao (12.1) uma manifestao da dualidade
de programao linear. (Veja o meu material [6] sobre o assunto.)
Os algoritmos do tipo primal-dual tm um certo carter guloso. No algoritmo
C OBERTURA B ARATA, por exemplo, as arestas so examinadas em ordem arbitrria e as
linhas 8-9 do algoritmo aumentam o valor de xp e xq o que torna mais provvel a
incluso de p e q em X o mximo possvel sem se preocupar com o objetivo global
de minimizar o custo da cobertura X.

Exerccio
12.2 Considere as instncias do Problema da Cobertura em que todos os vrtices tm o mesmo
custo. D um algoritmo de aproximao para essas instncias que seja mais simples que
C OBERTURA B ARATA. O seu algoritmo deve produzir uma cobertura de tamanho no superior ao dobro do timo.

12.5

Instncias especiais do problema

Um grafo bipartido se seu conjunto de vrtices admite uma bipartio (U, W ) tal que
toda aresta tem uma ponta em U e outra em W . (Portanto, U e W so coberturas.)
Existe um algoritmo muito elegante e eficiente para o Problema da Cobertura restrito a grafos bipartidos. (Veja a Seo 22.4 do livro de Sedgewick [19], por exemplo.)
O algoritmo consome (nm) unidades de tempo no pior caso, sendo n o nmero de
vrtices e m o nmero de arestas do grafo.

Notas bibliogrficas
Este captulo foi baseado no livro de Kleinberg e Tardos [10].

Captulo 13

Conjuntos independentes em grafos


Considere a relao amigode entre os usurios de um site de relacionamentos. Queremos encontrar um conjunto mximo de usurios que sejam amigos dois a dois.
Um problema da mesma natureza (mas computacionalmente mais fcil) j foi estudado no Captulo 8: encontrar um conjunto mximo de intervalos dois a dois compatveis.

13.1

O problema

Um conjunto I de vrtices de um grafo independente se seus elementos so dois a


dois no vizinhos, ou seja, se nenhuma aresta do grafo tem ambas as pontas em I. Um
conjunto independente I mximo se no existe um conjunto independente I 0 tal que
|I 0 | > |I|.
Problema do Conjunto Independente: Encontrar um conjunto independente
mximo num grafo dado.
Conjuntos independentes so os complementos das coberturas (veja o Captulo 12).
De fato, em qualquer grafo (V, A), se I um conjunto independente ento V I uma
cobertura. Reciprocamente, se C uma cobertura ento V C um conjunto independente. Portanto, encontrar um conjunto independente mximo computacionalmente
equivalente a encontrar uma cobertura mnima. No se conhecem bons algoritmos
para esses problemas.
Apesar da relao de complementaridade, algoritmos de aproximao para o Problema da Cobertura (como o que discutimos na Seo 12.3) no podem ser convertidos
em algoritmos de aproximao para o Problema do Conjunto Independente. De fato,
se uma cobertura mnima num grafo de n vrtices tiver apenas 100 vrtices e se nosso
algoritmo de aproximao obtiver uma cobertura com 199 vrtices, o correspondente
conjunto independente ter n 199 vrtices. Mas este nmero no menor que uma
percentagem fixa do tamanho de um conjunto independente mximo.

63

64

FEOFILOFF

Discutiremos a seguir um algoritmo probabilstico muito simples, que fornece um


conjunto independente de tamanho esperado razoavelmente grande, embora modesto.

Exerccio
13.1 Mostre que o problema dos intervalos compatveis discutido no Captulo 8 um caso
especial (ou seja, uma coleo de instncias) do problema do conjunto independente.
13.2 Um conjunto independente I em um grafo maximal se no existe um conjunto independente I 0 no grafo tal que I 0 I. Mostre que um conjunto independente maximal pode ser
arbitrariamente menor que um conjunto independente mximo.

13.2

Algoritmo probabilstico


Convm lembrar que todo grafo com n vrtices tem entre 0 e n2 arestas. Portanto, se
m o nmero de arestas ento 0 2m n2 n. O algoritmo que discutiremos a seguir
produz um conjunto independente I cujo tamanho esperado
n2 /4m .
O resultado intuitivamente razovel: quanto mais denso o grafo, ou seja, quanto mais
prximo m de n2 , menor o tamanho esperado de I.
m

n/2

2n

10n

n2 /4m

n/2

n/4

n/8

n/40

n n/4

n2 /4

(n2 n)/2

n/(2n 2)

Figura 13.1: Comparao entre o nmero m de arestas e o tamanho esperado


do conjunto independente produzido pelo algoritmo C ONJ I NDEPENDENTE.

O algoritmo recebe um grafo com vrtices 1, 2, . . . , n e conjunto A de arestas e


devolve um conjunto independente I tal que
|I| n/2 se m n/2 e
E[|I|] n2 /4m se m > n/2,
sendo m := |A|. A expresso E[x] denota o valor esperado de x.

65

ANLISE DE ALGORITMOS

C ONJ I NDEPENDENTE (n, A)


1 para i 1 at n faa
2
X[i] 1
3 m |A|
4 se 2m > n
5
ento para i 1 at n faa
6
r R ANDOM (2m 1)
7
se r < 2m n
8
ento X[i] 0
9 para cada ij em A faa
10
se X[i] = 1 e X[j] = 1
11
ento X[i] 0
12 devolva X[1 . . n]
O conjunto independente que o algoritmo devolve representado pelo vetor booleano X indexado pelos vrtices: i pertence ao conjunto independente se e somente
se X[i] = 1.
A rotina R ANDOM um gerador de nmeros aleatrios. Com argumento U , ela
produz um nmero natural uniformemente distribudo no conjunto {0, 1, 2 . . . , U }. (
muito difcil obter nmeros verdadeiramente aleatrios, mas existem bons algoritmos
para gerar nmeros pseudoaleatrios.)
O algoritmo est correto. O algoritmo tem duas fases. Na primeira fase (linhas 18), o algoritmo elimina vrtices at que sobre um conjunto W . Se m n/2, W o
conjunto de todos os vrtices. Caso contrrio, os vrtices so eliminados com probabilidade 1 n/2m, ou seja, permanecem em W na proporo de n em cada 2m. (Se

m = 10n, por exemplo, sobra 1 vrtice em cada 20. Se m = 12 n n, sobra 1 em cada n.


Se m = n2 /4, sobram cerca de 2 vrtices apenas.)
fcil determinar o tamanho esperado de W uma vez que cada um dos n vrtices
fica em W com probabilidade n/2m. Se w := |W | ento
E[w] = n

n2
n
=
.
2m
2m

Considere agora o conjunto B das arestas que tm ambas as pontas em W . Como o


grafo tem m arestas e a probabilidade de uma ponta de aresta ficar em W n/2m,
temos
 n 2
n2
E[b] = m
=
,
2m
4m
sendo b := |B|.
Na segunda fase (linhas 9-11), o algoritmo elimina vrtices de W de modo que
o conjunto restante I seja independente. Esta segunda fase do algoritmo remove no
mximo b vrtices e portanto o tamanho esperado de I
E[|I|] E[w] E[b] =

n2
n2
n2

=
.
2m 4m
4m

66

FEOFILOFF

Se executarmos o algoritmo um bom nmero de vezes e escolhermos o maior dos


conjuntos independentes que resultar, temos uma boa chance de obter um conjunto
independente de tamanho no menor que n2 /4m.
Consumo de tempo. O algoritmo linear. razovel supor que cada execuo
da rotina R ANDOM consome tempo independente de n e de m. Assim, o algoritmo
consome
(n + m)
unidades de tempo, sendo (n) unidades na primeira fase e (m) unidades na segunda.

13.3

Comentrios sobre algoritmos probabilsticos

Diz-se que um algoritmo probabilstico ou aleatorizado se usa nmeros aleatrios.


Cada execuo de um tal algoritmo d uma resposta diferente e o algoritmo promete
que o valor esperado da resposta suficientemente bom. Em geral, o algoritmo executado muitas vezes e o usurio escolhe a melhor das respostas.
Alguns algoritmos (no o caso do algoritmo C ONJ I NDEPENDENTE acima) prometem tambm que a resposta fornecida est prxima do valor esperado com alta probabilidade.
Os algoritmos probabilsticos ignoram, em geral, a estrutura e as peculiaridades da
instncia que esto resolvendo. Mesmo assim, surpreendentemente, muitos algoritmos
probabilsticos produzem resultados bastante teis.

Notas bibliogrficas
O algoritmo deste captulo descrito, por exemplo, no livro de Mitzenmacher e Upfal [15]. Sobre algoritmos aleatorizados em geral, veja o verbete Randomized algorithm
na Wikipedia.

Captulo 14

Busca em largura num grafo


Considere a relao amigode entre os usurios de uma rede social. Digamos que dois
usurios A e B esto ligados se existe uma sucesso de amigos que leva de A a B.
Suponha que queremos determinar todos os usurios ligados a um dado usurio.
A melhor maneira de resolver esse problema fazer uma busca num grafo (veja a
Seo 12.1).

14.1

O problema do componente

Um caminho em um grafo qualquer sequncia (i1 , i2 , . . . , iq ) de vrtices tal que cada


ip vizinho de ip1 para todo p 2. Dizemos que um vrtice est ligado a outro se
existe um caminho que comea no primeiro e termina no segundo. O conjunto de todos
os vrtices ligados a um vrtice v o componente (do grafo) que contm v.
Problema do Componente: Dado um vrtice v de um grafo, encontrar o conjunto de todos os vrtices ligados a v.
Este um dos mais bsicos e corriqueiros problemas sobre grafos.

14.2

Busca em largura: verso preliminar

Usaremos a estratgia da busca em largura para resolver o problema. Comearemos


por escrever uma verso preliminar do algoritmo, em alto nvel de abstrao.
Dizemos que dois vrtices i e j so vizinhos se ij uma aresta. A vizinhana de
um vrtice i o conjunto de todos os vizinhos de i e ser denotada por Z(i).
O seguinte algoritmo recebe um vrtice v de um grafo representado por seu conjunto V de vrtices e suas vizinhanas Z(i), i V , e devolve o conjunto de todos os
vrtices ligados a v.

67

68

FEOFILOFF

C OMPONENTE P RELIM (V, Z, v)


1 P
2 C {v}
3 enquanto C 6= faa
4
seja i um elemento de C
5
para cada j em Z(i) faa
6
se j
/ C P
7
ento C C {j}
8
C C {i}
9
P P {i}
10 devolva P
Voc pode imaginar que os vrtices em P so pretos, os vrtices em C so cinza e
todos os demais so brancos. Um vrtice branco enquanto no tiver sido visitado. Ao
ser visitado, o vrtice fica cinza e assim permanece enquanto todos os seus vizinhos
no tiverem sido visitados. Quando todos os vizinhos forem visitados, o vrtice fica
preto.
O algoritmo est correto. Considere o processo iterativo no bloco de linhas 3-9.
A cada passagem pela linha 3, imediatamente antes da comparao de C com , temos
os seguintes invariantes:
i.
ii.
iii.
iv.

P C = ,
v P C,
todo vrtice em P C est ligado a v e
toda aresta com uma ponta em P tem a outra ponta em P C.

evidente que estas propriedades valem no incio da primeira iterao. Suponha agora
que elas valem no incio de uma iterao qualquer. claro que i e ii continuam valendo
no incio da prxima iterao. No caso do invariante iii, basta verificar que os vrtices
acrescentados a P C durante esta iterao esto todos ligados a v. Para isso, suficiente observar que i est ligado a v (invariante iii) e portanto todos os vrtices em Z(i)
tambm esto ligados a v.
Finalmente, considere o invariante iv. Por um lado, o nico vrtice acrescentado a
P durante a iterao corrente i. Por outro lado, ao final da iterao, todos os vizinhos
de i esto em P C. Assim, o invariante iv continua vlido no incio da prxima
iterao.
No fim do processo iterativo, C est vazio. De acordo com os invariantes ii e iv,
todos os vrtices de qualquer caminho que comea em v esto em P . Reciprocamente,
todo vrtice em P est ligado a v, de acordo com invariante iii. Portanto, P o conjunto
de vrtices ligados a v. Assim, ao devolver P , o algoritmo cumpre o que prometeu.
Consumo de tempo. No h como discutir o consumo de tempo do algoritmo
de maneira precisa, pois no especificamos estruturas de dados que representem as
vizinhanas Z(i) e os conjuntos P e C.

69

ANLISE DE ALGORITMOS

Podemos garantir, entretanto, que a execuo do algoritmo termina depois de no


mais que |V | iteraes do bloco de linhas 4-9. De fato, no decorrer da execuo do
algoritmo, cada vrtice entra em C (linha 7) no mximo uma vez, faz o papel de i na
linha 4 no mximo uma vez, transferido de C para P (linhas 8 e 9) e portanto nunca
mais entra em C. Assim, o nmero de iteraes no passa de |V |.

Exerccios
14.1 Um grafo conexo se seus vrtices esto ligados dois a dois. Escreva um algoritmo que
decida se um grafo conexo.
14.2 Escreva um algoritmo que calcule o nmero de componentes de um grafo.

14.3

Busca em largura: verso mais concreta

Podemos tratar agora de uma verso mais concreta do algoritmo C OMPONENTE P RE LIM , que adota estruturas de dados apropriadas para representar os vrios conjuntos
de vrtices.
Suponha que os vrtices do grafo so 1, 2, . . . , n. As vizinhanas dos vrtices sero
representadas por uma matriz Z com linhas indexadas pelos vrtices e colunas indexadas por 1, 2, . . . , n 1. Os vizinhos de um vrtice i sero
Z[i, 1], Z[i, 2], . . . , Z[i, g[i]] ,
onde g[i] o grau de i, ou seja, o nmero de vizinhos de i. (Na prtica, usam-se listas
encadeadas para representar essas vizinhanas.) Observe que cada aresta ij aparece
exatamente duas vezes nesta representao: uma vez na linha i da matriz Z e outra vez
na linha j.
Os conjuntos P e C da seo anterior sero representados por um vetor cor indexado pelos vrtices: cor [i] valer 2 se i P , valer 1 se i C e valer 0 nos demais
casos. O conjunto C ter tambm uma segunda representao: seus elementos ficaro
armazenados num vetor F [a . . b], que funcionar como uma fila com incio a e fim b.
Isso permitir implementar de maneira eficiente o teste C 6= na linha 3 de C OMPO NENTE P RELIM, bem como a escolha de i em C na linha 4.
O algoritmo recebe um grafo com vrtices 1, 2, . . . , n, representado por seu vetor de
graus g e sua matriz de vizinhos Z e recebe um vrtice v. O algoritmo devolve um vetor
cor [1 . . n] que representa o conjunto de vrtices ligados a v (os vrtices do componente
so os que tm cor 2).

70

FEOFILOFF

C OMPONENTE (n, g, Z, v)
1 para i 1 at n faa
2
cor [i] 0
3 cor [v] 1
4 ab1
5 F [b] v
6 enquanto a b faa
7
i F [a]
8
para h 1 at g[i] faa
9
j Z[i, h]
10
se cor [j] = 0
11
ento cor [j] 1
12
bb+1
13
F [b] j
14
cor [i] 2
15
aa+1
16 devolva cor [1 . . n]
O algoritmo C OMPONENTE est correto pois o cdigo no faz mais que implementar o algoritmo C OMPONENTE P RELIM, que j discutimos.
Consumo de tempo. SejaP
m o nmero de arestas do grafo. (Em termos dos parmetros do algoritmo, m 12 ni=1 g[i].) Adotaremos o par (n, m) como medida do
tamanho de uma instncia do problema.
Podemos supor que uma execuo de qualquer das linhas do algoritmo consome
uma quantidade de tempo que no depende de n nem de m. A linha 7 executada n
vezes no pior caso, pois cada vrtice do grafo faz o papel de i na linha 7 uma s vez ao
longo da execuo do algoritmo. (Segue da, em particular, que b n.) Para cada valor
fixo de i, o bloco de linhas 9-13 executado g[i] vezes. Segue dessas duas observaes
que, no pior caso, o processo iterativo nas linhas 6-15 consome tempo proporcional
soma
n
X
g[i] ,
i=1

que vale 2m. O consumo desse processo iterativo est, portanto, em (m) no pior caso.
Como o consumo de tempo das linhas 1-5 est em (n), o consumo de tempo total
do algoritmo est em
(n + m)
no pior caso. (No melhor caso, o vrtice v no tem vizinhos e portanto o algoritmo
consome apenas (n) unidades de tempo.)

Exerccio
14.3 Escreva um algoritmo que calcule um caminho de comprimento mnimo dentre os que
ligam dois vrtices dados de um grafo. (O comprimento de um caminho o nmero de
arestas do caminho.)

Captulo 15

Busca em profundidade num grafo


Este captulo trata de um segundo algoritmo para o problema estudado no captulo
anterior.
Problema do Componente: Dado um vrtice v de um grafo, encontrar o conjunto de todos os vrtices ligados a v.
O algoritmo que discutiremos a seguir usa a estratgia da busca em profundidade. A importncia do algoritmo transcende em muito o problema do componente.
O algoritmo serve de modelo para solues eficientes de vrios problemas mais complexos, como o de calcular os componentes biconexos de um grafo, por exemplo.

15.1

Busca em profundidade

O seguinte algoritmo recebe um vrtice v de um grafo e devolve o conjunto de todos os


vrtices ligados a v. O conjunto de vrtices do grafo {1, . . . , n} e o conjunto de arestas
representado pelas vizinhanas Z(p), j definidas na Seo 14.2.
C OMPONENTE (n, Z, v)
1 para p 1 at n faa
2
cor [p] 0
3 B USCA E M P ROFUNDIDADE (v)
4 devolva cor [1 . . n]
O vetor cor , indexado pelo vrtices, representa a soluo: um vrtice p est ligado
a v se e somente se cor [p] = 2.
O algoritmo C OMPONENTE apenas uma casca que repassa o servio para a
rotina recursiva B USCA E M P ROFUNDIDADE. Do ponto de vista desta rotina, o grafo e o
vetor cor so variveis globais (a rotina pode, portanto, consultar e alterar o valor das
variveis).

71

72

FEOFILOFF

B USCA E M P ROFUNDIDADE (p)


5 cor [p] 2
6 para cada q em Z(p) faa
7
se cor [q] = 0
8
ento B USCA E M P ROFUNDIDADE (q)
O vetor cor s tem dois valores: 0 e 2. Diremos que um vrtice p branco se
cor [p] = 0 e preto se cor [p] = 2. Diremos tambm que um caminho (veja Seo 14.1)
branco se todos os seus vrtices so brancos. A rotina B USCA E M P ROFUNDIDADE pinta
de preto alguns dos vrtices que eram brancos. Assim, um caminho que era branco
quando a rotina foi invocada pode deixar de ser branco durante a execuo da rotina.
Podemos dizer agora o que a rotina B USCA E M P ROFUNDIDADE faz. Ela recebe um
vrtice branco p que vizinho de um vrtice preto a menos que seja igual a v e
pinta de preto todos os vrtices que estejam ligados a p por um caminho branco. (A
rotina no altera as cores dos demais vrtices.)
Agora que deixamos claro o problema que a rotina B USCA E M P ROFUNDIDADE resolve, importante adotar uma boa definio de tamanho das instncias desse problema. O nmero de vrtices e arestas do grafo no d uma boa medida do tamanho
da instncia, pois a rotina ignora boa parte do grafo. bem mais apropriado dizer que
o tamanho da instncia o nmero
X
g(x) ,
(15.1)
xX

onde X o conjunto dos vrtices ligados a p por caminhos brancos e g(x) := |Z(x)| o
grau do vrtice x.
A rotina est correta. A prova da correo da rotina B USCA E M P ROFUNDIDADE
uma induo no tamanho da instncia. Se o tamanho for 0, o vrtice p no tem vizinhos.
Se o tamanho for 1, o nico vrtice em Z(p) preto. Em qualquer desses casos, a rotina
cumpre o que prometeu.
Suponha agora que o tamanho da instncia maior que 1. Seja B o conjunto de
vrtices brancos no incio da execuo da rotina e seja X o conjunto dos vrtices ligados
a p em B. Queremos mostrar que no fim do processo iterativo descrito nas linhas 6-8 o
conjunto dos vrtices brancos B X.
Sejam q1 , q2 , . . . , qk os elementos de Z(p) na ordem em que eles sero examinados
na linha 6. Para j = 1, 2, . . . , k, seja Yj o conjunto dos vrtices ligados a qj em B {p}.
claro que X = {p} Y1 Yk .
Se Yi Yj 6= ento Yi = Yj . De fato, se Yi e Yj tm um vrtice em comum ento
existe um caminho em B {p} com origem qi e trmino em Yj . Portanto tambm existe
um caminho em B {p} de qi a qj , donde qj Yi . Segue da que Yj Yi . Um raciocnio
anlogo mostra que Yi Yj .
O processo iterativo descrito nas linhas 6-8 pode ser reescrito como
6
7
8

para j 1 at k faa
se cor [qj ] = 0
ento B USCA E M P ROFUNDIDADE (qj )

73

ANLISE DE ALGORITMOS

e isso permite formular o seguinte invariante: a cada passagem pela linha 6,



o conjunto dos vrtices brancos B {p} Y1 Yj1 .

(15.2)

Esta propriedade certamente vale no incio da primeira iterao. Suponha agora que
ela vale no incio de uma iterao qualquer. Se tivermos Yj = Yi para algum i entre 1
e j 1 ento, no incio desta iterao, todos os vrtices em Yj j so pretos e a linha 8 no
executada. Caso contrrio, Yj disjunto de Y1 Yj1 e portanto
os vrtices
 todosP
em Yj esto ligados a qj por caminhos em B {p} Y1 Yj1 . Como yYj g(y)
P
menor que xX g(x), podemos supor, por hiptese de induo, que a invocao de
B USCA E M P ROFUNDIDADE na linha 8 com argumento qj produz o resultado prometido.

Assim, no fim desta iterao, o conjunto dos vrtices brancos B {p} Y1 Yj .
Isto prova que (15.2) continua valendo no incio da prxima iterao.
No fim do processo iterativo, o invariante (15.2) garante que o conjunto de vrtices
brancos B {p}) Y1 Yk , ou seja, B X. Logo, B USCA E M P ROFUNDIDADE
cumpre o que prometeu.
Consumo de tempo. A anlise da correo da rotina B USCA E M P ROFUNDIDADE
permite
concluir que o consumo de tempo da rotina proporcional ao tamanho,
P
xX g(x), da instncia.
P Em particular, o consumo de tempo da linha 3 de C OM PONENTE no passa de
xV g(x). Como esta soma igual ao dobro do nmero de
arestas do grafo, m, podemos dizer que a linha 3 de C OMPONENTE consome
O(m)
unidades de tempo. No pior caso, o consumo (m).
Se levarmos em conta o consumo de tempo das linhas 1-2 de C OMPONENTE, teremos um consumo total de
(n + m)
unidades de tempo no pior caso.

Exerccio
15.1 Escreva e analise uma verso no recursiva do algoritmo B USCA E M P ROFUNDIDADE.

74

FEOFILOFF

Posfcio
O texto fez uma modesta introduo Anlise de Algoritmos usando material dos
excelentes livros citados na bibliografia. Embora tenha tratado apenas de problemas
e algoritmos muito simples, espero que este minicurso possa guiar o leitor que queira
analisar os seus prprios algoritmos.
O tratamento de algoritmos probabilsticos foi muito superficial e muitos outros
assuntos ficaram de fora por falta de espao. Assim, no foi possvel discutir a anlise
de tipos abstratos de dados, como filas de prioridades e estruturas union/find. A anlise
amortizada (muito til para estimar o consumo de tempo dos algoritmos de fluxo em
redes, por exemplo) foi igualmente ignorada. Finalmente, no foi possvel mencionar
a teoria da complexidade de problemas e a questo P=NP.

75

Bibliografia
[1] J.L. Bentley. Programming Pearls. ACM Press, second edition, 2000. 9, 27, 31, 32, 36
[2] G. Brassard and P. Bratley. Fundamentals of Algorithmics. Prentice Hall, 1996. 9, 22,
23, 42, 54, 58
[3] T.H. Cormen, C.E. Leiserson, R.L. Rivest, and C. Stein. Introduction to Algorithms.
MIT Press and McGraw-Hill, second edition, 2001. 9, 11, 22, 50, 54, 55, 59
[4] S. Dasgupta, C.H. Papadimitriou, and U.V. Vazirani. Algorithms. McGraw-Hill,
2006. 42
[5] A.C.P.L. de Carvalho and T. Kowaltowski, editors. Atualizaes em Informtica 2009.
SBC (Soc. Bras. de Computao). PUC-Rio, 2009. ISBN 978-85-87926-54-8. 7
[6] P. Feofiloff. Algoritmos de Programao Linear. Internet http://www.ime.usp.
br/~pf/prog-lin/, 1999. 206 pginas. 62
[7] P. Feofiloff. Anlise de Algoritmos.
analise_de_algoritmos/, 2011.

Internet http://www.ime.usp.br/~pf/

[8] C.G. Fernandes, F.K. Miyazawa, M. Cerioli, and P. Feofiloff, editors. Uma Introduo Sucinta a Algoritmos de Aproximao. XXIII Colquio Brasileiro de Matemtica.
IMPA (Instituto de Matemtica Pura e Aplicada), Rio de Janeiro, 2001. Internet
http://www.ime.usp.br/~cris/aprox/. 58
[9] J. Hromkovic. Algorithmics for Hard Problems: Introduction to Combinatorial Optimization, Randomization, Approximation, and Heuristics. Springer, second edition,
2004.
[10] J. Kleinberg and E. Tardos. Algorithm Design. Addison-Wesley, 2005. 9, 42, 46, 62
[11] D.E. Knuth. Seminumerical Algorithms, volume 2 of The Art of Computer Programming. Addison-Wesley, third edition, 1997. 42
[12] D.E. Knuth. Selected Papers on Analysis of Algorithms. CSLI Lecture Notes, no. 102.
Center for the Study of Language and Information (CSLI), Stanford, CA, 2000. 9
[13] D.E. Knuth. The Art of Computer Programming. Addison-Wesley, ca. 1973. Several
volumes.
77

[14] U. Manber. Introduction to Algorithms: A Creative Approach. Addison-Wesley, 1989.


9, 36
[15] M. Mitzenmacher and E. Upfal. Probability and Computing: Randomized Algorithms
and Probabilistic Analysis. Cambridge University Press, 2005. 66
[16] R. Neapolitan and K. Naimipour. Foundations of Algorithms. Jones and Bartlett,
second edition, 1998.
[17] I. Parberry. Problems on Algorithms. Prentice Hall, 1995. 50
[18] I. Parberry and W. Gasarch. Problems on Algorithms. Internet: http://www.eng.
unt.edu/ian/books/free/, second edition, 2002. 50
[19] R. Sedgewick. Algorithms in C, Part5: Graph Algorithms. Addison-Wesley, third
edition, 2000. 62
[20] J.L. Szwarcfiter and L. Markenzon. Estruturas de Dados e seus Algoritmos. Livros
Tcnicos e Cientficos, second edition, 1994.
[21] N. Ziviani. Projeto de Algoritmos (com implementaes em Pascal e C). Thomson,
second edition, 2004.

ndice remissivo
bxc, 11, 12
dxe, 12
lg n, 11
( ), 14
( ), 15
N, 12
N> , 12
R, 12
R , 12
R> , 12
algoritmo, 9
aleatorizado, 66
correto, 9
de aproximao, 57
de Karatsuba, 40
ene-log-ene, 16
exponencial, 16
guloso, 43, 44, 54
linear, 16
ineartmico, 16
Mergesort, 25
polinomial, 16
primal-dual, 62
probabilstico, 66
quadrtico, 16
recursivo, 11, 25, 39, 44, 49, 52, 71
anlise assinttica, 13
aproximao (algoritmo de), 57
aresta (de grafo), 59
assintoticamente no decrescente, 22
assinttico, 13
Bentley, 9, 27, 31, 32, 36
BFS, 67
Brassard, 9, 22, 23, 42, 54, 58
Bratley, 9, 22, 23, 42, 54, 58
breadth-first search, 67
bucket sort, 33
busca

em largura, 67
em profundidade, 71
caminho (em grafo), 67
cobertura (de grafo), 59
compatveis (intervalos), 43
componente (de grafo), 67
conexo (grafo), 69
conjunto independente (em grafo), 63
consumo de tempo, 10
Cormen, 9, 11, 22, 50, 54, 55, 59
correo (de algoritmo), 9
crescente, 25
Dasgupta, 42
depth-first search, 71
DFS, 71
dgito, 37
dgitos (nmero de), 37
diviso e conquista, 22, 26, 29, 42
eficincia, 10
estrutura recursiva
de um problema, 11, 32, 44, 48, 51
firmeza (de vetor), 30
fortemente polinomial, 54
Gasarch, 50
grafo, 59
bipartido, 62
conexo, 69
grau de vrtice, 69
guloso (algoritmo), 43, 44, 54
induo matemtica, 11, 14, 18, 25
instncia de problema, 9
intercalao de vetores, 25, 26
intervalo, 43
invariante, 28, 31, 35, 49, 50, 53, 61, 68, 73

79

80
Karatsuba, 40
Kleinberg, 9, 42, 46, 62
Knuth, 9, 42
Leiserson, 9
lg n, 12
log, 11
maioria, 33
majoritrio, 33
Manber, 9, 36
maximal, 64
melhor caso, 10
Mergesort, 25
minimal, 60
mnimo, 60
Mitzenmacher, 66
mochila
de valor mximo, 51
de valor quase mximo, 55
multiplicao de nmeros, 37
N, 12
N> , 12
no decrescente, 22
notao
O grande, 13
mega grande, 14
Teta grande, 15
NP-difcil, 54, 55, 59
nmero de dgitos, 37
nmeros
naturais, 12
reais, 12
O( ), 13
( ), 14
O grande, 13
mega () grande, 14
Ofman, 42
palavra, 47
Papadimitriou, 42
pargrafo, 47
Parberry, 50
pen drive, 54
pior caso, 10
piso de logaritmo, 11
piso de nmero, 11, 12
pontas (de aresta), 59
primal-dual, 62
problema, 9

FEOFILOFF

programao dinmica, 30, 32, 44, 49, 52


programao linear, 62
proporcional, 15
prova por
contradio, 13, 15
induo matemtica, 11, 14, 18, 25
R, 12
R , 12
R> , 12
recorrncia, 17
recurso, 11
recursivo (algoritmo), 11, 25, 39, 44, 49, 52, 71
Rivest, 9
Sedgewick, 62
segmento (de vetor), 27
solidez (de vetor), 27
Stein, 9
suficientemente grande, 13
svvm, 44
( ), 15
tamanho de instncia, 10
Tardos, 9, 42, 46, 62
tem n dgitos, 37
tempo (consumo de), 10
teorema mestre, 22
Teta () grande, 15
teto de nmero, 12
unidade de tempo, 10, 16
Upfal, 66
valor especfico, 55
valor majoritrio, 33
Vazirani, 42
vrtice (de grafo), 59
vetor crescente, 25
vivel, 43, 51, 55
vizinhos (vrtices), 67

You might also like