Você está na página 1de 80

Minicurso de

Anlise de Algoritmos
http://www.ime.usp.br/~pf/livrinho-AA/
Paulo Feoloff
Departamento de Cincia da Computao
Instituto de Matemtica e Estatstica
Universidade de So Paulo
2 de janeiro de 2013
2 FEOFILOFF
Sumrio
1 Introduo 9
1.1 Problemas e instncias . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2 Consumo de tempo de algoritmos . . . . . . . . . . . . . . . . . . . . 10
1.3 Recurso e algoritmos recursivos . . . . . . . . . . . . . . . . . . . . . 11
1.4 Convenes de notao . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2 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
3 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
4 Ordenao de vetor 25
4.1 Algoritmo Mergesort . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.2 Diviso e conquista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
5 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
3
4 FEOFILOFF
6 O problema da maioria 33
6.1 O problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.2 Um algoritmo linear . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
7 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
8 Escalonamento de intervalos 43
8.1 O problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
8.2 A estrutura recursiva do problema . . . . . . . . . . . . . . . . . . . . 44
8.3 Algoritmo de programao dinmica . . . . . . . . . . . . . . . . . . . 44
9 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 5
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
Bibliograa 77
ndice remissivo 79
6 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 maio-
ria em ingls). Este livrinho faz uma modesta introduo ao assunto. Depois de tratar
brevemente de alguns pr-requisitos (como notao assinttica e resoluo de recorrn-
cias), o texto analisa alguns algoritmos clssicos, discute sua ecincia, e chama a aten-
o para as estratgias (diviso e conquista, programao dinmica, mtodo primal-
dual) 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.
7
8 FEOFILOFF
Captulo 1
Introduo
AAnlise de Algoritmos
1
estuda certos problemas computacionais recorrentes, ou seja,
problemas que aparecem, sob diversos disfarces, em uma grande variedade de aplica-
es 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 eciente.
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.
Numnvel mais abstrato, a anlise de algoritmos procura identicar aspectos estru-
turais 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
xaremos 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 computa-
cional uma coleo de instncias.
2
Cada instncia do problema denida por um
particular conjunto de dados.
1
A expresso foi cunhada por D. E. Knuth [12].
2
Apalavra instncia umneologismo importado do ingls. Ela est sendo empregada aqui no sentido
de exemplo, espcime, amostra, ilustrao.
9
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 pro-
blema 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 instn-
cia A[1 . . n] n. (Dependendo das circunstncias, entretanto, pode ser mais apropri-
ado 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 quanti-
dade 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
ecincia 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 algo-
ritmo / 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 / 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 / no melhor caso.


Por exemplo, um algoritmo pode consumir 200n unidades de tempo no melhor
caso e 10n
2
+ 100n unidades no pior. (Estou ignorando os valores pequenos de n, para
os quais 200n maior que 10n
2
+ 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 neces-
srio descrever os algoritmos de maneira sucientemente 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 11
1.3 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 ma-
temtica 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
SOMAPOSITIVOS (A, n)
1 se n = 0
2 ento devolva 0
3 seno s SOMAPOSITIVOS (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 SOMAPOSITIVOS com argumentos A e n 1 produz o resultado prome-
tido. 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 x|. x
Para todo nmero natural n 1, o piso do logaritmo de n na base 2, denotado por lg n
lg n|, o nico nmero natural k tal que 2
k
n < 2
k+1
.
O seguinte algoritmo recursivo recebe um nmero natural n 1 e devolve lg n|:
3
Usaremos a excelente notao do livro de Cormen et al. [3] para descrever algoritmos.
12 FEOFILOFF
PISODELOG (n)
1 se n = 1
2 ento devolva 0
3 seno devolva PISODELOG (n/2|) + 1
Prova da correo do algoritmo: Se n = 1, evidente que o algoritmo devolve o
valor correto de lg n|. Agora tome n 2 e seja k o nmero lg n|. Queremos mostrar
que o algoritmo devolve k.
Como 2
k
n < 2
k+1
, temos 2
k1
n/2 < 2
k
. Como 2
k1
um nmero natural,
temos 2
k1
n/2| < 2
k
e portanto lgn/2|| = k 1. Como n/2| < n, podemos
supor, por hiptese de induo, que o valor da expresso PISODELOG (n/2|) k 1.
Portanto, o algoritmo devolve k 1 + 1 = k, como queramos provar.
1.4 Convenes de notao
Para concluir esta introduo, estabelecemos algumas convenes de notao. Denota-
remos por N o conjunto 0, 1, 2, 3, . . . dos nmeros naturais (que coincide com o dos N
inteiros no negativos). O conjunto N 0 ser denotado por N
>
. O conjunto dos N
>
nmeros reais ser denotado por R. O conjunto dos reais no negativos e o dos reais R
estritamente positivos sero denotados por R

e por R
>
respectivamente. R

R
>
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 emN tal que j 1 < x j. O piso
e o teto de x so denotados por x| e ,x| respectivamente. x
Denotaremos por lg n o logaritmo de um nmero n na base 2. Portanto, lg n =
log
2
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 gros-
seiro 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 2n
2
, por exemplo,
cresce to rpido quanto 10n
2
) e despreza valores pequenos do argumento (a funo
n
2
cresce mais rpido que 100n, embora n
2
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 Gde NemR

, dizemos que F est em O(G) se existemc e n


0
emN
>
tais que
F(n) c G(n)
para todo n n
0
. A mesma coisa pode ser dita assim: existe c em N
>
tal que F(n)
c G(n) para todo n sucientemente 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(n
2
), pois 100n n n = n
2
para todo n 100.
Exemplo 2: 2n
3
+100n est emO(n
3
). De fato, para todo n 1 temos 2n
3
+100n
2n
3
+ 100n
3
102n
3
. Eis outra maneira de provar que 2n
3
+ 100n est em O(n
3
): para
todo n 100 tem-se 2n
3
+ 100n 2n
3
+n n n = 3n
3
.
Exemplo 3: n
1.5
est em O(n
2
), pois n
1.5
n
0.5
n
1.5
= n
2
para todo n 1.
Exemplo 4: n
2
/10 no est em O(n). Eis uma prova deste fato. Tome qualquer c
13
14 FEOFILOFF
em N
>
. Para todo n > 10c temos n
2
/10 = n n/10 > 10c n/10 = cn. Logo, no
verdade que n
2
/10 cn para todo n sucientemente grande.
Exemplo 5: 2n est emO(2
n
). De fato, 2n 2
n
para todo n 1, como provaremos
por induo em n. Prova: Se n = 1, a armao verdadeira pois 2 1 = 2
1
. Agora
tome n 2 e suponha, a ttulo de hiptese de induo, que 2(n 1) 2
n1
. Ento
2n 2(n + n 2) = 2(n 1) + 2(n 1) 2
n1
+ 2
n1
= 2
n
, como queramos
demonstrar.
A seguinte regra da soma til: se F e F

esto ambas em O(G) ento F + F

tambm est em O(G). Eis uma prova da regra. Por hiptese, existem nmeros c
e n
0
tais que F(n) cG(n) para todo n n
0
. Analogamente, existem c

e n

0
tais
que F

(n) c

G(n) para todo n n

0
. Ento, para todo n max(n
0
, n

0
), tem-se
F(n) +F

(n) (c +c

)G(n).
Exemplo 6: Como 2n
3
e 100n esto ambas em O(n
3
), a funo 2n
3
+100n tambm
est em O(n
3
).
Nossa denio da notao Ofoi formulada para funes de NemR

, mas ela pode


ser estendida, da maneira bvia, a funes que no esto denidas ou so negativas
para valores pequenos do argumento.
Exemplo 7: Embora n
2
100n no esteja em R

quando n < 100, podemos dizer


que n
2
100n O(n
2
), pois n
2
100n n
2
para todo n 100.
Exemplo 8: Embora lg n no esteja denida quando n = 0, podemos dizer que lg n
est em O(n). De fato, se tomarmos o logaritmo da desigualdade n 2
n
do Exemplo 5,
veremos que lg n n para todo n 1.
Exemplo 9: nlg n est em O(n
2
). Segue imediatamente do Exemplo 8.
Exerccios
2.1 Critique a armao n
2
100n est em O(n
2
) para todo n 100.
2.2 Mostre que lg n est em O(n
0.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
F(n)
1
c
G(n)
para todo n sucientemente 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: n
3
+ 100n est em (n
3
), pois n
3
+ 100n n
3
para todo n.
A denio da notao pode ser estendida, da maneira bvia, a funes F ou G
que esto denidas e so no negativas apenas para valores grandes de n.
ANLISE DE ALGORITMOS 15
Exemplo 11: n
2
2n (n
2
). De fato, temos 2n
1
2
n
2
para todo n 4 e portanto
n
2
2n n
2

1
2
n
2
=
1
2
n
2
.
Exemplo 12: nlg n est em (n). De fato, para todo n 2 tem-se lg n 1 e
portanto nlg n n.
Exemplo 13: 100n no est em (n
2
). Tome qualquer c em N
>
. Para todo n >
100c, tem-se 100 <
1
c
n e portanto 100n <
1
c
n
2
.
Exemplo 14: n no (2
n
). Basta mostrar que para qualquer c em N
>
tem-se
n <
1
c
2
n
para todo n sucientemente grande. Como todo c menor que alguma po-
tncia de 2, basta mostrar que, para qualquer k em N
>
, tem-se n 2
k
2
n
para todo n
sucientemente grande. Especicamente, mostraremos que n 2
nk
para todo n 2k.
A prova por induo em n. Se n = 2k, temos k 2
k1
conforme o Exemplo 5
com k no papel de n, e portanto n = 2k 2 2
k1
= 2
k
= 2
2kk
= 2
nk
. Agora tome
n 2k + 1 e suponha, a ttulo de hiptese de induo, que n 1 2
n1k
. Ento
n n + n 2 = n 1 + n 1 = 2 (n 1) 2 2
n1k
= 2
nk
, como queramos
demonstrar.
Exerccios
2.3 Mostre que 2
n1
est em (2
n
).
2.4 Mostre que lg n no (n).
2.3 Notao Teta
Dizemos que F est em (G) se F est emO(G) e tambmem(G), ou seja, se existem
c e c

emN
>
tais que
1
c
G(n) F(n) c

G(n)
para todo n sucientemente 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 an
2
+ bn est
em (n
2
).
Exerccio
2.5 Mostre que n(n + 1)/2 e n(n 1)/2 esto em (n
2
).
2.4 Consumo de tempo de algoritmos
Seja / um algoritmo para um problema cujas instncias tm tamanho n. Se a funo
que mede o consumo de tempo de /no pior caso est emO(n
2
), por exemplo, podemos
16 FEOFILOFF
usar expresses como
/ consome O(n
2
) unidades de tempo no pior caso
e / consome tempo O(n
2
) no pior caso. Podemos usar expresses semelhantes com
ou no lugar de O e melhor caso no lugar de pior caso.
(Se / consome tempo O(n
2
) no pior caso, tambm consome O(n
2
) em qualquer
caso. Analogamente, se consome (n
2
) no melhor caso, tambm consome (n
2
) em
qualquer caso. Mas no podemos dispensar a clusula no pior caso em uma arma-
o como / consome tempo (n
2
) 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 tama-
nho da entrada dobra, o algorimo consome duas vezes mais tempo; quando o tama-
nho 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 (nlg n) no pior
caso. Se o tamanho da entrada dobra, o consumo dobra e acrescido de 2n; se o ta-
manho multiplicado por uma constante c, o consumo multiplicado por c e acrescido
de um pouco mais que cn.
Um algoritmo quadrtico se consome tempo (n
2
) no pior caso. Se o tamanho
da entrada dobra, o consumo quadruplica; se o tamanho multiplicado por uma
constante c, o consumo multiplicado por c
2
.
Polinomial e exponencial. Um algoritmo polinomial se consome tempo O(n
k
)
no pior caso, sendo k um nmero natural. Por exemplo, polinomial qualquer algo-
ritmo que consome O(n
100
) unidades de tempo. Apesar desse exemplo, algoritmos
polinomiais so considerados rpidos.
Um algoritmo exponencial se consome tempo (a
n
) no pior caso, sendo a um
nmero real maior que 1. Por exemplo, exponencial qualquer algoritmo que consome
(1.1
n
) 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, / e B, resolvem um mesmo problema. Suponha que o ta-
manho das instncias do problema medido por um parmetro n. Em quais dos seguintes
casos podemos armar que / mais rpido que B? Caso 1: / consome tempo O(lg n) no
pior caso e B consome tempo O(n
3
) no pior caso. Caso 2: / consome O(n
2
lg n) unida-
des de tempo no pior caso e B consome (n
2
) unidades de tempo no pior caso. Caso 3:
No pior caso, / consome O(n
2
) unidades de tempo e B consome (n
2
lg n) unidades de
tempo.
Captulo 3
Soluo de recorrncias
Ahabilidade de resolver recorrncias importante para a anlise do consumo de tempo
de algoritmos recursivos. Uma recorrncia uma frmula que dene uma funo,
digamos F, em termos dela mesma. Mais precisamente, dene 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 denida
explicitamente em termos de n.
3.1 Exemplo 1
Seja F uma funo de N emR
>
. 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
=
= 2
j
F(n j) + 2
j
1
= 2
n1
F(1) + 2
n1
1 .
Conclumos assim que
F(n) = 2
n
1 (3.2)
para todo n 1. (No temos informaes sobre o valor de F(0).) Portanto, F est
em (2
n
).
17
18 FEOFILOFF
Exerccios
3.1 Conra a frmula (3.2) por induo em n.
3.2 Sejam a, b e n
0
trs nmeros naturais e suponha que F(n
0
) = a e F(n) = 2F(n 1) + b
para todo n > n
0
. Mostre que F est em (2
n
).
3.2 Exemplo 2
Suponha que uma funo F de N emR
>
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) =
1
2
(n
2
+n) (3.4)
para todo n 1. (No temos informaes sobre o valor de F(0).) Portanto, F est
em (n
2
).
Recorrncias semelhantes. O valor de F(1) tem pouca inuncia sobre o resul-
tado. Se tivssemos F(1) = 10, por exemplo, a frmula (3.4) seria substituda por
F(n) =
1
2
(n
2
+n) + 9, e esta funo tambm est em (n
2
).
O ponto a partir do qual (3.3) comea a valer tambm tem pouca inuncia sobre a
soluo da recorrncia. Se (3.3) valesse apenas a partir de n = 5, por exemplo, teramos
F(n) =
1
2
(n
2
+n) +F(4) 10 no lugar de (3.4), e esta funo tambm est em (n
2
).
Exerccios
3.3 Conra (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) = 3n
2
/2 + 7n/2 4 para todo n 2. Conclua que F est
em (n
2
).
3.5 Sejam a, b e c trs nmeros naturais e suponha que F satisfaz as seguintes condies:
F(n
0
) = a e F(n) = F(n 1) +bn +c para todo n > n
0
. Mostre que F est em (n
2
).
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 emR
>
. Suponha que F satisfaz a recorrncia
F(n) = 2F(n/2|) +n (3.5)
ANLISE DE ALGORITMOS 19
para todo n 2. (No faz sentido trocar n/2| 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 n/2| se
reduz a n/2. Se n = 2
j
, temos
F(2
j
) = 2F(2
j1
) + 2
j
= 2
2
F(2
j2
) + 2
1
2
j1
+ 2
j
= 2
3
F(2
j3
) + 2
2
2
j2
+ 2
1
2
j1
+ 2
j
= 2
j
F(2
0
) + 2
j1
2
1
+ + 2
2
2
j2
+ 2
1
2
j1
+ 2
0
2
j
= 2
j
2
0
+ 2
j1
2
1
+ + 2
2
2
j2
+ 2
1
2
j1
+ 2
0
2
j
= (j + 1)2
j
= j2
j
+ 2
j
. (3.6)
Para ter certeza, podemos conferir esta frmula por induo em j. Se j = 1, temos
F(2
j
) = 4 = (j + 1)2
j
. Agora tome j 2. De acordo com (3.5), F(2
j
) = 2F(2
j1
) + 2
j
.
Por hiptese de induo, F(2
j1
) = 2
j1
j. Logo, F(2
j
) = 2 2
j1
j +2
j
= 2
j
j +2
j
, como
queramos mostrar.
Como 2
j
= n, a expresso (3.6) pode ser reescrita assim:
F(n) = nlg n +n (3.7)
quando n potncia de 2. Embora esta frmula s se aplique s potncias de 2, po-
demos us-la para obter cotas superior e inferior vlidas para todo n sucientemente
grande. O primeiro passo nessa direo vericar 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(
n
2
) + n + 1 =
2F(
n+1
2
|)+n+1 = F(n+1), emvirtude de (3.5). Agora suponha n mpar. Por hiptese
de induo, F(
n1
2
) F(
n1
2
+ 1) = F(
n+1
2
). Logo, por (3.5),
F(n) = 2F(
n1
2
) +n 2F(
n+1
2
) +n < 2F(
n+1
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). Mostrare-
mos que
F(n) 6nlg n (3.9)
para todo n 2. Tome o nico j em N tal que 2
j
n < 2
j+1
. Em virtude de (3.8),
F(n) < F(2
j+1
). Em virtude de (3.6), F(2
j+1
) = (j + 2)2
j+1
3j2
j+1
= 6j2
j
. Como
j lg n, temos 6j2
j
6nlg n.
Uma boa cota inferior para F tambm pode ser calculada a partir de (3.7): mostra-
remos que
F(n)
1
2
nlg n (3.10)
20 FEOFILOFF
para todo n 2. Tome o nico j em N tal que 2
j
n < 2
j+1
. Em virtude de (3.8)
e (3.6), temos F(n) F(2
j
) = (j + 1)2
j
=
1
2
(j + 1)2
j+1
. Como lg n < j + 1, temos
1
2
(j + 1)2
j+1
>
1
2
nlg n.
De (3.9) e (3.10), conclumos que F est em (nlg n).
Recorrncias semelhantes. O ponto n
0
a partir do qual a recorrncia (3.5) comea
a valer, bem como os valores de F(1), F(2), . . . , F(n
0
1), tm pouca inuncia so-
bre a soluo da recorrncia: quaisquer que sejam esses valores iniciais, F estar em
(nlg n). Se (3.5) vale apenas para n 3, por exemplo, teremos nlg n +
F(2)2
2
n no
lugar de (3.7).
Aparcela n na expresso 2F(n/2|)+n tambmpode ser ligeiramente alterada sem
que F saia de (nlg n). Assim, quaisquer que sejam c > 0 e d, se F(n) = 2F(n/2|) +
cn +d ento F est em (nlg n).
Finalmente, podemos trocar 2F(n/2|) por 2F(,n/2|) ou at mesmo por
F(n/2|) +F(,n/2|) sem que F saia de (nlg n).
Mas o fator 2 que multiplica F(n/2|) crtico: se este fator for alterado, a funo
F deixar de pertencer a (nlg n).
Exerccios
3.7 Suponha que um funo F de N em R
>
satisfaz a recorrncia F(n) = F(n/2|) + 1 para
todo n 2. Mostre que F est em (lg n).
3.8 Seja F uma funo de N emR
>
tal que F(n) = 2F(n/2|) +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(n/2|) + n quando n 2. Mostre que
F est em (n
2
). Sugesto: mostre que
1
4
n
2
F(n) 8n
2
para todo n sucientemente
grande.
3.4 Exemplo 4
Seja F um funo de N emR
>
. Suponha que
F(n) = 3F(n/2|) +n (3.11)
para todo n 2. Suponha ainda que F(1) = 1. Para comear a entender o comporta-
mento de F, considere os valores de n que so potncias de 2. Quando n = 2
j
, temos
F(2
j
) = 3F(2
j1
) + 2
j
= 3
2
F(2
j2
) + 3
1
2
j1
+ 2
j
= 3
3
F(2
j3
) + 3
2
2
j2
+ 3
1
2
j1
+ 2
j
= 3
j
F(2
0
) + 3
j1
2
1
+ + 3
2
2
j2
+ 3
1
2
j1
+ 3
0
2
j
= 3
j
2
0
+ 3
j1
2
1
+ + 3
2
2
j2
+ 3
1
2
j1
+ 3
0
2
j
ANLISE DE ALGORITMOS 21
= 2
j

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

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

(3/2)
j+1
1

= 3
j+1
2
j+1
. (3.12)
Observe que 3
j
= (2
lg 3
)
j
= (2
j
)
lg 3
= n
lg 3
. (A ttulo de curiosidade, lg 3 ca entre 1.584
e 1.585.) Portanto, a frmula (3.12) pode ser reescrita assim:
F(n) = 3n
lg 3
2n
para toda potncia n de 2. Embora esta frmula s valha para as potncias de 2, po-
demos us-la para obter cotas superior e inferior vlidas para todo n sucientemente
grande. A primeira providncia nessa direo certicar-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) 9n
lg 3
(3.13)
para todo n 1. Tome j emNtal que 2
j
n < 2
j+1
. Como F crescente, (3.12) garante
que F(n) < F(2
j+1
) = 3
j+2
2
j+2
3
j+2
= 9 (2
j
)
lg 3
9n
lg 3
, como queramos
mostrar. Tambm podemos calcular uma boa cota inferior:
F(n)
1
3
n
lg 3
(3.14)
para todo n 1. Tome j emNtal que 2
j
n < 2
j+1
. Como F crescente, (3.12) garante
que F(n) F(2
j
) = 3
j+1
2
j+1
= 3
j
+2 3
j
2 2
j
3
j
=
1
3
3
j+1
=
1
3
(2
j+1
)
lg 3
>
1
3
n
lg 3
,
como queramos demonstrar.
As relaes (3.13) e (3.14) mostram que F est em (n
lg 3
).
Recorrncias semelhantes. Se (3.11) valesse apenas quando n n
0
, a funo F
continuaria em (n
lg 3
) quaisquer que fossem os valores de F(n
0
/2|), F(n
0
/2| + 1),
. . . , F(n
0
1).
Alm disso, F continuar em (n
lg 3
) se (3.11) for substituda por F(n) =
3F(n/2|) + cn + d, quaisquer que sejam c > 0 e d. Tambm continuar em (n
lg 3
) se
3F(n/2|) for trocado por 2F(n/2|) +F(,n/2|) ou at mesmo por 2F(n/2|) +
F(,n/2| + 1).
Exerccio
3.10 Conra a formula (3.12) por induo em j.
22 FEOFILOFF
3.5 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 emN
>
, N e R
>
respectivamente. Seja F uma funo de N
emR
>
tal que
F(n) = a F

n
2

+cn
k
(3.15)
para n = 2
1
, 2
2
, 2
3
, . . . Suponha ainda que F assintoticamente no decrescente, ou
seja, que existe n
1
tal que F(n) F(n + 1) para todo n n
1
. Nessas condies,
se lg a > k ento F est em (n
lg a
), (3.16)
se lg a = k ento F est em (n
k
lg n), (3.17)
se lg a < k ento F est em (n
k
). (3.18)
(Recorrncias como (3.15) aparecem na anlise de algoritmos baseados na estrat-
gia 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 cn
k
.)
Generalizao. Oteorema pode ser generalizado como segue. Sejama 1, b 2,
k 0 e n
0
1 nmeros em N e seja c um nmero em R
>
. Seja F uma funo de N
emR
>
tal que
F(n) = a F

n
b

+cn
k
(3.19)
para n = n
0
b
1
, n
0
b
2
, n
0
b
3
, . . . Suponha ainda que F assintoticamente no decrescente.
Nessas condies,
se lg a/ lg b > k ento F est em (n
lg a/ lg b
), (3.20)
se lg a/ lg b = k ento F est em (n
k
lg n), (3.21)
se lg a/ lg b < k ento F est em (n
k
). (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(n/2|) +2F(,n/2|) +cn para todo n 2. Nessas condies, F no decres-
cente e portanto (3.16) garante que F est em (n
lg 3
). (Compare com o resultado da
Seo 3.4.)
Exemplo B. Sejama e k nmeros emN tais que a > 2
k
e seja c um nmero emR
>
.
Seja F uma funo de N em R
>
tal que F(n) = aF

n/2|

+ cn
k
para todo n 1.
Nessas condies, F no decrescente e portanto (3.16) garante que F est em (n
lg a
).
ANLISE DE ALGORITMOS 23
Notas bibliogrcas
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 eciente do Problema da Ordenao:
MERGESORT (A, p, r)
1 se p < r
2 ento q (p +r)/2|
3 MERGESORT (A, p, q)
4 MERGESORT (A, q+1, r)
5 INTERCALA (A, p, q, r)
A rotina INTERCALA 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 ins-
tncia (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 algo-
ritmo aplicado a instncias do problema que tm tamanho estritamente menor que n
(tamanho ,n/2| na linha 3 e tamanho n/2| 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 INTERCALA, A[p . . r] estar em ordem crescente no
m da linha 5.
25
26 FEOFILOFF
p q q+1 r
111 333 555 555 777 888 222 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(,n/2|) +T(n/2|) +n .
As parcelas T(,
n
2
|) e T(
n
2
|) correspondem s linhas 3 e 4. A parcela n representa o
consumo de tempo da linha 5, uma vez que o algoritmo INTERCALA pode ser imple-
mentado 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
(nlg n) .
O consumo de tempo do algoritmo no melhor caso tambm est em (nlg n).
Exerccio
4.1 Descreva em pseudocdigo o algoritmo INTERCALA mencionado acima. Mostre que o
consumo de tempo do algoritmo (n).
4.2 Diviso e conquista
Oalgoritmo MERGESORT emprega a estratgia da diviso e conquista: a instncia origi-
nal do problema dividida emduas 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 ecientes para muitos proble-
mas. 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 eciente 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 temelementos 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 ca ligeiramente mais
simples se nos limitarmos aos segmentos no vazios.
27
28 FEOFILOFF
5.2 Primeiro algoritmo
Se aplicarmos cegamente a denio de solidez, teremos que examinar todos os pares
ordenados (i, j) tais que p i j r. Esse algoritmo consumiria (n
3
) unidades de
tempo. Mas possivel fazer algo mais eciente:
SOLIDEZI (A, p, r)
1 x A[r]
2 para q r 1 decrescendo at p faa
3 s 0
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 li-
nha 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. Oconsumo de tempo do algoritmo ser medido emrelao
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 xo 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

q=p
(r q + 1) = n + (n 1) + + 3 + 2 =
1
2
(n
2
+n 2) .
Portanto, o consumo de tempo est em (n
2
), tanto no pior quanto no melhor caso.
Oalgoritmo ineciente porque a soma de cada segmento recalculada muitas ve-
zes. 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 inecincia.
Exerccios
5.1 Modique o algoritmo SOLIDEZI 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 umalgoritmo anlogo a SOLIDEZI 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.
ANLISE DE ALGORITMOS 29
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
nalmente juntar as duas solues. O algoritmo devolve a solidez do vetor A[p . . r]
supondo p r:
SOLIDEZII (A, p, r)
1 se p = r
2 ento devolva A[p]
3 seno q (p +r)/2|
4 x

SOLIDEZII (A, p, q)
5 x

SOLIDEZII (A, q + 1, r)
6 y

s A[q]
7 para i q 1 decrescendo at p faa
8 s A[i] +s
9 se s > y

ento y

s
10 y

s A[q + 1]
11 para j q + 2 at r faa
12 s s +A[j]
13 se s > y

ento y

s
14 x max (x

, y

+y

, x

)
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, x

a solidez de A[p . . q]. Depois da


linha 5, x

a solidez de A[q+1 . . r]. Depois do bloco de linhas 6-13, y

+ y

a maior
soma da forma A[i] + +A[j] com i q < j. (Veja o Exerccio 5.3.)
Em suma, y

+y

cuida dos segmentos que contm A[q] e A[q+1], enquanto x

e x

cuidam de todos os demais segmentos. Conclumos assim que o nmero x calculado


na linha 14 a solidez de A[p . . r].
p q q+1 r
20 30 15 10 30 20 30 30
Figura 5.2: Incio da linha 14 do algoritmo SOLIDEZII.
Nesse ponto, x

= 20, x

= 30, y

= 5 e y

= 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(,n/2|) +T(n/2|) +n .
A parcela T(,n/2|) descreve o consumo da linha 4 e a parcela T(n/2|) descreve o con-
sumo da linha 5. Esta recorrncia j foi discutida nas Sees 3.3 e 3.5, onde mostramos
que T est em
(nlg n) .
O algoritmo SOLIDEZII mais eciente que SOLIDEZI pois nlg n O(n
2
) enquanto
n
2
no O(nlg n). Mas SOLIDEZII tem suas prprias inecincias, 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 inecincias.
Exerccio
5.3 Prove que depois do bloco de linhas 6-13 do algoritmo SOLIDEZII, y

+ y

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 ar-
mazenar os resultados de clculos intermedirios numa tabela para evitar que eles se-
jam 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 rmeza do vetor A[p . . r]. A solidez do vetor o mximo das rmezas de A[p . . r],
A[p . . r1], A[p . . r2], etc.
Armeza do vetor temuma propriedade recursiva que a solidez no tem. Suponha
que A[i]+ +A[r] a rmeza de A[p . . r]. Se i r1 ento A[i]+ +A[r1] a rmeza
de A[p . . r1]. (De fato, se A[p . . r1] tivesse rmeza 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 rmeza de A[p . . q] por F[q], podemos resumir a propriedade re-
cursiva 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:
ANLISE DE ALGORITMOS 31
SOLIDEZIII (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. Acada passagempela linha 2, imediatamente antes que
q seja comparado com r, F[q 1] a rmeza de A[p . . q1]. Mais que isso,
F[j] a rmeza 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 rmezas. Portanto, no m 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 r
A 20 30 15 10 30 20 30 30
F 20 10 15 5 35 15 15 30
Figura 5.3: Vetores A e F no m da execuo do algoritmo SOLIDEZIII.
Exerccios
5.4 Os dois processos iterativos de SOLIDEZIII podemser fundidos nums, 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 Ben-
tley [1, p.84].)
32 FEOFILOFF
5.5 Observaes sobre programao dinmica
O algoritmo SOLIDEZIII 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 so-
lues 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 bibliogrcas
Este captulo foi baseado no livro de Bentley [1].
2
Aqui, a palavra programao no tem relao direta com programao de computadores. Ela signica
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 deter-
minar, em tempo proporcional ao nmero de eleitores, se algum dos candidatos obteve
a maioria
1
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
1
2
(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 ele-
mento, e vericar se alguma dessas contagens supera n/2. A ordenao do vetor con-
some (nlg n) unidades de tempo se usarmos o algoritmo MERGESORT (veja o Cap-
tulo 4).
2
As contagens no vetor ordenado consomem (n). Portanto, o algoritmo todo
consumir (nlg 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 (nlg 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
Umalgoritmo eciente para o problema comea coma seguinte observao: se A[1 . . n]
tem um valor majoritrio e se A[n 1] ,= A[n] ento A[1 . . n2] tambm tem um va-
lor majoritrio. (A observao se aplica igualmente a quaisquer dois elementos: se
A[i] ,= 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 vericar se um bom candidato , de fato,
majoritrio: basta percorrer o vetor e contar o nmero de ocorrncias do candidato. A
diculdade 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):
MAJORITRIO (A, n)
1 x A[1]
2 y 1
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 y 1
ANLISE DE ALGORITMOS 35
10 c 0
11 para m 1 at n faa
12 se A[m] = x
13 ento c c + 1
14 se c > n/2
15 ento devolva x
16 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
1
2
(mk +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 vericada 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
1
2
(mk), 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 = m1.
Na ltima passagem pela linha 3 temos m = n + 1 e portanto existe k no intervalo
1 . . n tal que A[1 . . k1] no temvalor majoritrio e x ocorre exatamente
1
2
(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 vericam se x de fato majoritrio.
Consumo de tempo. razovel supor que o consumo de tempo de uma execu-
o 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 di-
versas 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
diculdade do problema est em inventar um algoritmo que seja mais rpido que o
algoritmo bvio.
Notas bibliogrcas
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 n
2
.
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 criptograa, por exemplo).
7.1 O problema
Usaremos notao decimal para representar nmeros naturais. (Poderamos igual-
mente bem usar notao binria, ou notao base 2
32
, por exemplo.) Diremos que um
dgito qualquer nmero menor que 10. Diremos que um nmero natural u tem n
dgitos
1
se u < 10
n
. Com esta conveno, podemos nos restringir, sem perder genera-
lidade, 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 dgi-
tos. Mas nossa discusso ser conduzida numnvel de abstrao alto, semmanipulao
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
comn dgitos cada. Asoma u+v temn+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 produ-
tos 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.
Oprimeiro passo do algoritmo consome tempo proporcional a n
2
. Osegundo passo
tambm consome tempo proporcional a n
2
. Assim, o consumo de tempo do algoritmo
usual de multiplicao est em (n
2
).
9999 A
7777 B
69993 C
69993 D
69993 E
69993 F
77762223 G
Figura 7.1: Algoritmo usual de multiplicao de dois nmeros naturais. Aqui es-
tamos multiplicando 9999 por 7777 para obter o produto 77762223. A linha C o
resultado da multiplicao da linha A pelo dgito menos signicativo da linha B. As
linhas D, E e F so denidas 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 nme-
ros 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
Sejamu e v dois nmeros comn 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 10
n/2
+q .
Dena r e s analogamente para v, de modo que v = r 10
n/2
+s. Teremos ento
u v = p r 10
n
+ (p s +q r) 10
n/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:
RASCUNHO (u, v, n)
1 se n = 1
2 ento devolva u v
3 seno m n/2
4 p u/10
m
|
5 q u mod 10
m
6 r v/10
m
|
7 s v mod 10
m
8 pr RASCUNHO (p, r, m)
9 qs RASCUNHO (q, s, m)
10 ps RASCUNHO (p, s, m)
11 qr RASCUNHO (q, r, m)
12 x pr 10
2m
+ (ps + qr) 10
m
+ 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. Analoga-
mente, 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 10
2m
e 10
m
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 (n
2
), como j vimos no Exerccio 3.9.
Assim, o algoritmo RASCUNHO no mais eciente que o algoritmo usual de multipli-
cao.
2
Minha calculadora de bolso no capaz de exibir/armazenar nmeros que tenham mais que n d-
gitos. 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 u
77776666 v
9999 p
8888 q
7777 r
6666 s
77762223 pr
59247408 qs
135775310 ps + qr
7777580112347408 x
Figura 7.2: Multiplicao de u por v calculada pelo algoritmo RASCUNHO. 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,
p s +q r = y p r q s ,
sendo y = (p +q) (r +s). Assim, a equao (7.1) pode ser substituda por
u v = p r 10
n
+ (y p r q s) 10
n/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 ,n/2|: teremos u = p 10
n/2
+q e v = r 10
n/2
+s e portanto
u v = p r 10
2n/2
+ (y p r q s) 10
n/2
+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:
KARATSUBA (u, v, n)
1 se n 3
2 ento devolva u v
3 seno m ,n/2|
4 p u/10
m
|
5 q u mod 10
m
6 r v/10
m
|
7 s v mod 10
m
8 pr KARATSUBA (p, r, m)
9 qs KARATSUBA (q, s, m)
10 y KARATSUBA (p +q, r +s, m+1)
11 x pr 10
2m
+ (y pr qs) 10
m
+ qs
12 devolva x
ANLISE DE ALGORITMOS 41
O algoritmo est correto. A prova da correo do algoritmo anloga prova
da correo do algoritmo RASCUNHO. 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 ,n/2| + 1, e este nmero s menor que n quando n > 3.
Consumo de tempo. Seja T(n) o consumo de tempo do algoritmo KARATSUBA
no pior caso. Ento
T(n) = 2 T(,n/2|) +T(,n/2| + 1) +n . (7.4)
As duas parcelas T(,n/2|) e a parcela T(,n/2| +1) se referem s linhas 8, 9 e 10 respec-
tivamente. 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

que satisfaz a recorrncia T

(n) = 3T

(n/2|) +n. De acordo com a Seo 3.4,


T

est em (n
lg 3
). Portanto
T est em (n
lg 3
) . (7.5)
Como lg 3 < 1.6, o algoritmo KARATSUBA mais rpido que o algoritmo usual. (Ob-
serve que n
lg 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 u
077766666 v
07769223 pr
5925807408 qs
98887 p +q
67443 r +s
6669235941 y
735659310 y pr qs
077765801856807408 x
Figura 7.3: Multiplicao de u por v calculada pelo algoritmo KARATSUBA. O resul-
tado da operao x. Se u e v tivessemn dgitos cada, pr e qs teriamn+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 n-
mero 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] 10
n1
+
U[n1] 10
n2
+ +U[2] 10 +U[1].
O algoritmo KARATSUBA 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
9 8 7 6 5 4 3 2 1
9 9 9 9 8 8 8 8 8
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 algo-
ritmo 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 10
2m
+ (y pr qs) 10
m
+ 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 KARATSUBA 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 bibliogrcas
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 KARATSUBA 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 a
1
, a
2
, . . . , a
n
e b
1
, b
2
, . . . , b
n
nmeros naturais tais que a
i
b
i
para cada i.
Cada ndice i representa o intervalo que tem origem a
i
e trmino b
i
, ou seja, o conjunto
a
i
, a
i
+1, . . . , b
i
1, b
i
.
Dois intervalos distintos i e j so compatveis se b
i
< a
j
ou b
j
< a
i
. Um conjunto
de intervalos vivel se seus elementos so compatveis dois a dois.
A cada intervalo i est associado um nmero natural v
i
que representa o valor
do intervalo. O valor de um conjunto S de intervalos o nmero v(S) :=

iS
v
i
.
Um conjunto vivel S tem valor mximo se v(S) v(S

) para todo conjunto S

de
intervalos que seja vivel.
Problema dos Intervalos Compatveis de Valor Mximo: Dados nmeros natu-
rais a
1
, . . . , a
n
, b
1
, . . . , b
n
e v
1
, . . . , v
n
tais que a
i
b
i
para cada i, encontrar um
subconjunto vivel de 1, . . . , n que tenha valor mximo.
A primeira ideia que vem mente a de um algoritmo guloso
1
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 v
1
v
2

v
n
. Agora considere o seguinte algoritmo. A m-sima iterao do algoritmo comea
comumsubconjunto vivel S de 1, . . . , m1. Se Sm 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 recur-
siva: qualquer soluo de uma instncia do problema contm solues de instncias
menores.
Para simplicar a descrio do conjunto de intervalos compatveis com n, convm
supor que os intervalos esto em ordem crescente de trminos, ou seja, que
b
1
b
2
b
n
. (8.1)
Sob esta hiptese, o conjunto dos intervalos compatveis com n simplesmente
1, . . . , j, sendo j o maior ndice tal que b
j
< a
n
.
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) +v
n

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

X(n 1) , v
n

.
Esta recorrncia pode ser facilmente transformada em um algoritmo recursivo. Mas o
algoritmo muito ineciente, 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 (2
n
). (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 bomproveito 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:
INTERVALOSCOMPATVEIS (a
1
, . . . , a
n
, b
1
, . . . , b
n
, v
1
, . . . , v
n
)
1 X[0] 0
2 para m 1 at n faa
3 j m1
4 enquanto j 1 e b
j
a
m
faa
5 j j 1
6 se X[m1] > X[j] +v
m
7 ento X[m] X[m1]
8 seno X[m] X[j] +v
m
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. Supo-
nha 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 INTERVA-
LOSCOMPATVEIS 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 execu-
es das diversas linhas.
Para cada valor xo de m, a linha 5 executada no mximo m1 vezes. Como m
varia de 1 a n e

n
m=1
(m 1) =
1
2
(n
2
n), a linha 5 executada menos que n
2
vezes.
Todas as demais linhas so executadas no mximo n 1 vezes. Logo, o consumo de
tempo total do algoritmo est em
O(n
2
)
no pior caso. Uma anlise um pouco mais cuidadosa mostra que o consumo est em
(n
2
) 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(nlg n) (veja o Captulo 4) e nlg n est em O(n
2
), o consumo de tempo total (n
2
).
(Mas veja o Exerccio 8.3.)
Exerccios
8.3 Mostre que o algoritmo INTERVALOSCOMPATVEIS pode ser implementado de modo a con-
sumir apenas O(n) unidades de tempo. Sugesto: construa uma tabela auxiliar que pro-
duza, em tempo constante, efeito equivalente ao das linhas 4-5.
8.4 Escreva umalgoritmo de ps-processamento que extraia da tabela X[1 . . n] produzida pelo
algoritmo INTERVALOSCOMPATVEIS um svvm de 1, . . . , n. O seu algoritmo deve con-
sumir O(n) unidades de tempo.
Notas bibliogrcas
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 sequn-
cia de caracteres. Queremos imprimir um pargrafo em uma ou mais linhas consecuti-
vas 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 que razoavelmente uniforme, queremos distribuir as
palavras pelas linhas de modo a minimizar a soma dos cubos dos espaos em branco
que sobram no m de todas as linhas exceto a ltima.
9.1 O problema
Para simplicar 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 c
n
, c
n1
, . . . , c
2
, c
1
de nmeros naturais. Diremos
tambmque cada c
i
uma palavra: c
n
a primeira palavra do pargrafo e c
1
a ltima.
Um trecho de um pargrafo c
n
, c
n1
, . . . , c
1
qualquer sequncia da forma
c
m
, c
m1
, . . . , c
k
com n m k 1. Este trecho ser denotado por (m, k). O compri-
mento do trecho (m, k) o nmero
c(m, k) := c
m
+ 1 +c
m1
+ 1 + + 1 +c
k
.
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 c
n
, c
n1
, . . . , c
1
uma subdiviso do pargrafo em
trechos curtos. Mais precisamente, uma L-decomposio uma sequncia
(n, k
q
), (k
q
1, k
q1
), (k
q1
1, k
q2
), . . . , (k
2
1, k
1
) (k
1
1, 1)
de trechos curtos em que n k
q
> k
q1
> > k
2
> k
1
> 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 ooooo-
ppppp qq r sss ttt uu.
Figura 9.1: Duas decomposies do mesmo pargrafo. As linhas tm capaci-
dade L = 30 e os caracteres - representam os espaos em branco que contri-
buem para o defeito. O defeito da primeira decomposio 0
3
+ 5
3
= 125 e o da
segunda 4
3
+ 1
3
= 65.
ccc bbb ccc
aaa bbb--
ccc
Figura 9.2: direita temos uma decomposio tima de um pargrafo c
3
, c
2
, c
1
. 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 par-
grafo c
2
, c
1
. esquerda, uma decomposio tima do pargrafo c
1
.
Problema da Decomposio de um Pargrafo: Dado umpargrafo c
n
, c
n1
, . . . ,
c
1
e umnmero natural L, encontrar uma L-decomposio tima do pargrafo.
claro que as instncias do problema em que c
i
> L para algumi no tm soluo.
Exerccios
9.1 Tente explicar por que a denio 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 c
i
= 1 para i = n, . . . , 1. Mostre que o defeito de uma decomposio tima
no mximo 2n/L|.
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
ANLISE DE ALGORITMOS 49
pargrafo c
n
, c
n1
, . . . , c
1
. Se k 2 ento
a correspondente decomposio de c
k1
, c
k2
, . . . , c
1
tima.
Eis a prova desta propriedade: Seja x o defeito da decomposio de c
k1
, . . . , c
1
indu-
zida pela decomposio tima de c
n
, . . . , c
1
. Suponha agora, por um momento, que o
pargrafo c
k1
, . . . , c
1
tem uma decomposio com defeito menor que x. Ento a com-
binao desta decomposio com o trecho (n, k) uma decomposio de c
n
, . . . , c
1
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 c
n
, c
n1
, . . . , c
1
. Se o
trecho (n, 1) curto ento X(n) = 0. Caso contrrio,
X(n) = min
c(n,k)L

(L c(n, k))
3
+X(k1)

, (9.1)
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 ineciente.
9.3 Um algoritmo de programao dinmica
Para usar a recorrncia (9.1) de maneira eciente, basta interpretar X como uma ta-
bela 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 de-
feito mnimo de um pargrafo c
n
, c
n1
, . . . , c
1
supondo n 1, linhas de capacidade L
e c
i
L para todo i:
DEFEITOMNIMO (c
n
, . . . , c
1
, L)
1 para m 1 at n faa
2 X[m]
3 k m
4 s c
m
5 enquanto k > 1 e s L faa
6 X

(L s)
3
+X[k1]
7 se X

< X[m] ento X[m] X

8 k k 1
9 s s + 1 +c
k
10 se s L ento X[m] 0
11 devolva X[n]
(No difcil modicar 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 terminamtipicamente
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[m1] o defeito mnimo do pargrafo c
m1
, . . . , c
1
,
X[m2] o defeito mnimo do pargrafo c
m2
, . . . , c
1
,
. . . ,
X[1] o defeito mnimo do pargrafo c
1
.
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 c
m
, c
m1
, . . . , c
1
usando a recorrncia (9.1).
No m do processo iterativo temos m = n + 1 e portanto X[n] o defeito mnimo
do pargrafo c
n
, . . . , c
1
.
Consumo de tempo. Adote n como tamanho da instncia (c
n
, . . . , c
1
, L) do pro-
blema. 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 determi-
nado pelo nmero de execues das vrias linhas.
Para cada valor xo 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
1
2
n(n 1). Portanto, o algoritmo consome
(n
2
)
unidades de tempo no pior caso. No melhor caso (que acontece, por exemplo, quando
c
i
,L/2| para cada i), o algoritmo consome (n) unidades de tempo.
Exerccio
9.4 Modique o algoritmo DEFEITOMNIMO para que ele devolva a descrio k
q
, k
q1
, . . . , k
1

de uma decomposio tima do pargrafo c


n
, . . . , c
1
e no apenas o defeito da decomposi-
o.
Notas bibliogrcas
O problema que discutimos neste captulo proposto como exerccio nos livros de Cor-
men 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 p
1
, . . . , p
n
e v
1
, . . . , v
n
. Diremos que p
i
o peso e v
i
o
valor de i. Para qualquer subconjunto S de 1, 2, . . . , n, sejam p(S) e v(S) os nmeros

iS
p
i
e

iS
v
i
respectivamente. Diremos que p(S) o peso e v(S) o valor de S.
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 p
1
, . . . , p
n
, c, v
1
, . . . , v
n
, encon-
trar 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 (2
n
).
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 (n1, p, c, v).
Se n S ento S n soluo de (n 1, p, c p
n
, v).
Podemos resumir isso dizendo que o problema tem estrutura recursiva: toda solu-
o 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 recur-
51
52 FEOFILOFF
siva do problema pode ser representada pela seguinte recorrncia:
X(n, c) = max

X(n 1, c) , X(n 1, c p
n
) +v
n

. (10.1)
O segundo termo de max s faz sentido se c p
n
0, e portanto
X(n, c) = X(n 1, c) (10.2)
quando p
n
> c.
Poderamos calcular X(n, c) recursivamente. Mas o algoritmo resultante muito
ineciente, 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 p
i
= v
i
= 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 eciente a partir da recorrncia (10.1-10.2), preciso armaze-
nar 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 p
i
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
MOCHILAPD (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 p
j
0
6 ento y X[j 1, b p
j
] +v
j
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 Exer-
ccio 10.4.
ANLISE DE ALGORITMOS 53
p
4
2
1
3
v
500
400
300
450
0 1 2 3 4 5
0 0 0 0 0 0 0
1 0 0 0 0 500 500
2 0 0 400 400 500 500
3 0 300 400 700 700 800
4 0 300 400 700 750 850
Figura 10.1: Uma instncia do Problema da Mochila com n = 4 e c = 5. A
gura mostra a tabela X[0 . . n, 0 . . c] calculada pelo algoritmo MOCHILAPD.
O algoritmo est correto. Acada passagempela 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.1-
10.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. Por-
tanto, basta contar o nmero de execues das diversas linhas.
Para cada valor xo 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 MOCHILAPD muito sensvel s variaes de c. Ima-
gine, 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 concei-
tualmente 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, ,lg c|), pois c pode ser escrito com apenas ,lg c| bits. mais razovel,
portanto, dizer que o algoritmo consome
(n2
lg c
)
unidades de tempo. Isto torna claro que o consumo de tempo cresce explosivamente
com lg c.
Gostaramos de ter umalgoritmo cujo consumo de tempo no dependesse do valor
de c, um algoritmo cujo consumo de tempo estivesse em O(n
2
), ou O(n
10
), ou O(n
100
).
(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 MOCHILAPD?
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 MOCHILAPD 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 p
i
. O algoritmo
MOCHILAPD 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 v
i
= p
i
para todo i, temos o clebre Problema Subset Sum, que pode ser apresentado
assim: imagine que voc emitiu cheques de valores v
1
, . . . , v
n
durante o ms; se o banco
debitou um total de c na sua conta no m do ms, quais podem ter sido os cheques
debitados?
Considere agora as instncias do Problema da Mochila em que v
i
= 1 para todo i.
(Voc pode imaginar que p
1
, . . . , p
n
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 eciente que
MOCHILAPD.
Notas bibliogrcas
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
Oalgoritmo de programao dinmica para o Problema da Mochila (veja o Captulo 10)
lento. Dada a diculdade de encontrar um algoritmo mais rpido,
1
faz sentido re-
duzir nossas exigncias e procurar por uma soluo quase tima. Um tal algoritmo
deve calcular um conjunto vivel de valor maior que uma frao predeterminada (di-
gamos 50%) do valor mximo.
11.1 O problema
Convm repetir algumas das denies da Seo 10.1. Dados nmeros naturais
p
1
, . . . , p
n
, c e v
1
, . . . , v
n
, diremos que p
i
o peso e v
i
o valor de i. Para qualquer
subconjunto S de 1, . . . , n, denotaremos por p(S) a soma

iS
p
i
e diremos que S
vivel se p(S) c. O valor de S o nmero v(S) :=

iS
v
i
. Um conjunto vivel S


timo se v(S

) v(S) para todo conjunto vivel S.


Problema da Mochila: Dados nmeros naturais p
1
, . . . , p
n
, c, v
1
, . . . , v
n
, encon-
trar 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 p
i
c (11.1)
para todo i.
11.2 Algoritmo de aproximao
Oalgoritmo que descreveremos a seguir temcarter guloso e d preferncia aos obje-
tos de maior valor especco. O valor especco de um objeto i o nmero v
i
/p
i
. Para
simplicar 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 especco, ou seja, que
v
1
p
1

v
2
p
2

v
n
p
n
. (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)
1
2
v(S

) ,
sendo S

um subconjunto vivel timo:


MOCHILAQUASETIMA (n, p, c, v)
1 X
2 s x 0
3 k 1
4 enquanto k n e s +p
k
c faa
5 X X k
6 s s +p
k
7 x x +v
k
8 k k + 1
9 se k > n ou x v
k
10 ento devolva X
11 seno devolva k
O bloco de linhas 4 a 8 determina o maior k tal que p
1
+ + p
k1
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)
1
2
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), v
k
)
1
2
v(S)
para todo conjunto vivel S. O primeiro passo da demonstrao consiste na seguinte
observao:
max (v(X), v
k
)
1
2
(v(X) +v
k
) =
1
2
v(R) ,
sendo R := X k. O segundo passo mostra que v(R) > v(S) qualquer que seja o
ANLISE DE ALGORITMOS 57
conjunto vivel S:
v(R) v(S) = v(R S) v(S R)
=

iRS
v
i

iSR
v
i
=

iRS
v
i
p
i
p
i

iSR
v
i
p
i
p
i

v
k
p
k
p(R S)
v
k
p
k
p(S R) (11.3)
=
v
k
p
k

p(R) p(S)

>
v
k
p
k

c c

(11.4)
= 0 .
A relao (11.3) vale porque v
i
/p
i
v
k
/p
k
para todo i em R e v
i
/p
i
v
k
/p
k
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 me-
dida 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 (nlg n) (veja o Captulo 4). Portanto, o consumo de tempo do processo todo
(nlg 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 MOCHILA-
QUASETIMA, por exemplo, melhor que 50% do timo. Esse fator de aproximao
pode parecer grosseiro, mas suciente para algumas aplicaes que precisam de um
algoritmo muito rpido.
58 FEOFILOFF
Outros algoritmos de aproximao para o Problema da Mochila tm fator de apro-
ximao bem melhor que 50%. O algoritmo de Ibarra e Kim (veja o livro de Fernan-
des 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 MOCHILAPD em que os papis de p e v so trocados.
(Veja o Exerccio 10.5.)
Notas bibliogrcas
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 suciente 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

V
2

. Cada elemento de A , por-


tanto, 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. Se cada vrtice i tem um custo c
i
, o custo de uma cobertura
X o nmero c(X) :=

iX
c
i
.
Problema da Cobertura: Dado um grafo cujos vrtices tm custos emN, encon-
trar 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 algo-
ritmo 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 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

tal que [X

[ < [X[. Uma cobertura X minimal


se no existe uma cobertura X

tal que X

X. Mostre que uma cobertura minimal pode


ser arbitrariamente maior que uma cobertura mnima.
12.3 Um algoritmo de aproximao
Oseguinte algoritmo recebe umgrafo (V, A) e umnmero natural c
i
para cada vrtice i
e devolve uma cobertura X tal que c(X) 2 c(X

), sendo X

uma cobertura de custo


mnimo:
COBERTURABARATA (V, A, c)
1 para cada i em V faa
2 x
i
0
3 para cada ij em A faa
4 y
ij
0
5 para cada pq em A faa
6 e min (c
p
x
p
, c
q
x
q
)
7 y
pq
y
pq
+e
8 x
p
x
p
+e
9 x
q
x
q
+e
10 X
11 para cada i em V faa
12 se x
i
= c
i
ento X X i
13 devolva X
O algoritmo atribui nmeros naturais y s arestas. Voc pode imaginar que y
pq

a quantia que a aresta pq paga a cada uma de suas pontas para convencer uma delas
a fazer parte da cobertura. Um vrtice p aceita participar da cobertura se

q
y
pq
c
p
,
sendo a soma feita sobre todas as arestas que tm ponta p. A regra do jogo nunca
pagar mais que o necessrio. Portanto,

q
y
pq
c
p
para todo vrtice p.
ANLISE DE ALGORITMOS 61
O algoritmo est correto. No incio de cada iterao do bloco de linhas 6-9, temos
os seguintes invariantes:
i. x
i
=

j
y
ij
para todo i em V ,
ii. x
i
c
i
para todo i em V ,
iii. para toda aresta ij j examinada tem-se x
i
= c
i
ou x
j
= c
j
.
Estas propriedades so obviamente verdadeiras no incio da primeira iterao. No
incio de cada iterao subsequente, o invariante i continua valendo, pois y
pq
, x
p
e x
q
so acrescidos da mesma quantidade e. O invariante ii continua valendo, pois e
c
p
x
p
e e c
q
x
q
. O invariante iii continua valendo, pois e = c
p
x
p
ou e = c
q
x
q
.
Os invariantes i e ii tm a seguinte consequncia: no incio de cada iterao do
bloco de linhas 6-9, temos

ijA
y
ij
c(Z) (12.1)
para qualquer cobertura Z. Para mostrar isso, basta observar que

ijA
y
ij

iZ

j
y
ij
=

iZ
x
i


iZ
c
i
. 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 m do bloco de linhas 10-12 temos
c(X) 2

ijA
y
ij
. (12.2)
De fato, como x
i
= c
i
para todo i em X, temos

iX
c
i
=

iX
x
i
=

iX

j
y
ij

2

ijA
y
ij
. A segunda igualdade vale em virtude do invariante i. A ltima desigual-
dade 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 cober-
tura Z,
c(X) 2 c(Z) .
Isto vale, em particular, se Z uma cobertura de custo mnimo. Como X uma cober-
tura (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 eciente 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 FEOFILOFF
12.4 Comentrios sobre o mtodo primal-dual
Oalgoritmo COBERTURABARATA 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
COBERTURABARATA, por exemplo, as arestas so examinadas em ordem arbitrria e as
linhas 8-9 do algoritmo aumentam o valor de x
p
e x
q
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
COBERTURABARATA. O seu algoritmo deve produzir uma cobertura de tamanho no su-
perior 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 eciente para o Problema da Cobertura res-
trito 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 bibliogrcas
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. Quere-
mos encontrar um conjunto mximo de usurios que sejam amigos dois a dois.
Um problema da mesma natureza (mas computacionalmente mais fcil) j foi estu-
dado no Captulo 8: encontrar um conjunto mximo de intervalos dois a dois compat-
veis.
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

tal que
[I

[ > [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 indepen-
dente. 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 Pro-
blema 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 xa 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 indepen-
dente I

no grafo tal que I

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

n
2

arestas. Portanto, se
m o nmero de arestas ento 0 2m n
2
n. O algoritmo que discutiremos a seguir
produz um conjunto independente I cujo tamanho esperado
n
2
/4m.
Oresultado intuitivamente razovel: quanto mais denso o grafo, ou seja, quanto mais
prximo m de n
2
, menor o tamanho esperado de I.
m n/2 n 2n 10n n

n/4 n
2
/4 (n
2
n)/2
n
2
/4m n/2 n/4 n/8 n/40

n 1 n/(2n 2)
Figura 13.1: Comparao entre o nmero m de arestas e o tamanho esperado
do conjunto independente produzido pelo algoritmo CONJINDEPENDENTE.
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[] n
2
/4m se m > n/2,
sendo m := [A[. A expresso E[x] denota o valor esperado de x.
ANLISE DE ALGORITMOS 65
CONJINDEPENDENTE (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 RANDOM (2m1)
7 se r < 2mn
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 bo-
oleano X indexado pelos vrtices: i pertence ao conjunto independente se e somente
se X[i] = 1.
A rotina RANDOM 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 1-
8), 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 proba-
bilidade 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 =
1
2
n

n, sobra 1 em cada

n.
Se m = n
2
/4, sobram cerca de 2 vrtices apenas.)
fcil determinar o tamanho esperado de W uma vez que cada um dos n vrtices
ca em W com probabilidade n/2m. Se w := [W[ ento
E[w] = n
n
2m
=
n
2
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 car em W n/2m,
temos
E[b] = m

n
2m

2
=
n
2
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] =
n
2
2m

n
2
4m
=
n
2
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 n
2
/4m.
Consumo de tempo. O algoritmo linear. razovel supor que cada execuo
da rotina RANDOM 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 se-
gunda.
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 sucientemente bom. Em geral, o algoritmo exe-
cutado muitas vezes e o usurio escolhe a melhor das respostas.
Alguns algoritmos (no o caso do algoritmo CONJINDEPENDENTE acima) prome-
tem tambm que a resposta fornecida est prxima do valor esperado com alta proba-
bilidade.
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 bibliogrcas
O algoritmo deste captulo descrito, por exemplo, no livro de Mitzenmacher e Up-
fal [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 (i
1
, i
2
, . . . , i
q
) de vrtices tal que cada
i
p
vizinho de i
p1
para todo p 2. Dizemos que um vrtice est ligado a outro se
existe umcaminho que comea no primeiro e termina no segundo. Oconjunto 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 con-
junto 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 con-
junto V de vrtices e suas vizinhanas Z(i), i V , e devolve o conjunto de todos os
vrtices ligados a v.
67
68 FEOFILOFF
COMPONENTEPRELIM (V, Z, v)
1 P
2 C v
3 enquanto C ,= 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 ca cinza e assim permanece enquanto todos os seus vizinhos
no tiverem sido visitados. Quando todos os vizinhos forem visitados, o vrtice ca
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. P C = ,
ii. v P C,
iii. todo vrtice em P C est ligado a v e
iv. toda aresta com uma ponta em P tem a outra ponta em P C.
evidente que estas propriedades valemno 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 vericar que os vrtices
acrescentados a P C durante esta iterao esto todos ligados a v. Para isso, suci-
ente 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 nal da iterao, todos os vizinhos
de i esto em P C. Assim, o invariante iv continua vlido no incio da prxima
iterao.
No m 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 emP est ligado a v, de acordo cominvariante 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 especicamos estruturas de dados que representem as
vizinhanas Z(i) e os conjuntos P e C.
ANLISE DE ALGORITMOS 69
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 COMPONENTEPRE-
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 indexa-
das 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 inde-
xado 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 caro
armazenados num vetor F[a . . b], que funcionar como uma la com incio a e m b.
Isso permitir implementar de maneira eciente o teste C ,= na linha 3 de COMPO-
NENTEPRELIM, 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 umvrtice v. Oalgoritmo devolve umvetor
cor[1 . . n] que representa o conjunto de vrtices ligados a v (os vrtices do componente
so os que tm cor 2).
70 FEOFILOFF
COMPONENTE (n, g, Z, v)
1 para i 1 at n faa
2 cor[i] 0
3 cor[v] 1
4 a b 1
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 b b + 1
13 F[b] j
14 cor[i] 2
15 a a + 1
16 devolva cor[1 . . n]
O algoritmo COMPONENTE est correto pois o cdigo no faz mais que implemen-
tar o algoritmo COMPONENTEPRELIM, que j discutimos.
Consumo de tempo. Seja m o nmero de arestas do grafo. (Em termos dos pa-
rmetros do algoritmo, m
1
2

n
i=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
xo 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

i=1
g[i] ,
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 con-
junto de todos os vrtices ligados a v.
O algoritmo que discutiremos a seguir usa a estratgia da busca em profundi-
dade. A importncia do algoritmo transcende em muito o problema do componente.
O algoritmo serve de modelo para solues ecientes de vrios problemas mais com-
plexos, 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 denidas na Seo 14.2.
COMPONENTE (n, Z, v)
1 para p 1 at n faa
2 cor[p] 0
3 BUSCAEMPROFUNDIDADE (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 COMPONENTE apenas uma casca que repassa o servio para a
rotina recursiva BUSCAEMPROFUNDIDADE. 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
BUSCAEMPROFUNDIDADE (p)
5 cor[p] 2
6 para cada q em Z(p) faa
7 se cor[q] = 0
8 ento BUSCAEMPROFUNDIDADE (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 BUSCAEMPROFUNDIDADE 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 BUSCAEMPROFUNDIDADE 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 BUSCAEMPROFUNDIDADE re-
solve, importante adotar uma boa denio de tamanho das instncias desse pro-
blema. 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

xX
g(x) , (15.1)
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 BUSCAEMPROFUNDIDADE
uma induo no tamanho da instncia. Se o tamanho for 0, o vrtice p no temvizinhos.
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 m do processo iterativo descrito nas linhas 6-8 o
conjunto dos vrtices brancos B X.
Sejam q
1
, q
2
, . . . , q
k
os elementos de Z(p) na ordem em que eles sero examinados
na linha 6. Para j = 1, 2, . . . , k, seja Y
j
o conjunto dos vrtices ligados a q
j
em B p.
claro que X = p Y
1
Y
k
.
Se Y
i
Y
j
,= ento Y
i
= Y
j
. De fato, se Y
i
e Y
j
tm um vrtice em comum ento
existe um caminho emBp com origemq
i
e trmino emY
j
. Portanto tambm existe
um caminho emBp de q
i
a q
j
, donde q
j
Y
i
. Segue da que Y
j
Y
i
. Um raciocnio
anlogo mostra que Y
i
Y
j
.
O processo iterativo descrito nas linhas 6-8 pode ser reescrito como
6 para j 1 at k faa
7 se cor[q
j
] = 0
8 ento BUSCAEMPROFUNDIDADE (q
j
)
ANLISE DE ALGORITMOS 73
e isso permite formular o seguinte invariante: a cada passagem pela linha 6,
o conjunto dos vrtices brancos B

p Y
1
Y
j1

. (15.2)
Esta propriedade certamente vale no incio da primeira iterao. Suponha agora que
ela vale no incio de uma iterao qualquer. Se tivermos Y
j
= Y
i
para algum i entre 1
e j1 ento, no incio desta iterao, todos os vrtices emY
j
j so pretos e a linha 8 no
executada. Caso contrrio, Y
j
disjunto de Y
1
Y
j1
e portanto todos os vrtices
em Y
j
esto ligados a q
j
por caminhos em B

p Y
1
Y
j1

. Como

yY
j
g(y)
menor que

xX
g(x), podemos supor, por hiptese de induo, que a invocao de
BUSCAEMPROFUNDIDADE na linha 8 comargumento q
j
produz o resultado prometido.
Assim, no m desta iterao, o conjunto dos vrtices brancos B

pY
1
Y
j

.
Isto prova que (15.2) continua valendo no incio da prxima iterao.
No m do processo iterativo, o invariante (15.2) garante que o conjunto de vrtices
brancos B

p) Y
1
Y
k

, ou seja, B X. Logo, BUSCAEMPROFUNDIDADE


cumpre o que prometeu.
Consumo de tempo. A anlise da correo da rotina BUSCAEMPROFUNDIDADE
permite concluir que o consumo de tempo da rotina proporcional ao tamanho,

xX
g(x), da instncia. Em particular, o consumo de tempo da linha 3 de COM-
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 COMPONENTE 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 COMPONENTE, tere-
mos um consumo total de
(n +m)
unidades de tempo no pior caso.
Exerccio
15.1 Escreva e analise uma verso no recursiva do algoritmo BUSCAEMPROFUNDIDADE.
74 FEOFILOFF
Posfcio
O texto fez uma modesta introduo Anlise de Algoritmos usando material dos
excelentes livros citados na bibliograa. 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 supercial e muitos outros
assuntos caram de fora por falta de espao. Assim, no foi possvel discutir a anlise
de tipos abstratos de dados, como las de prioridades e estruturas union/nd. A anlise
amortizada (muito til para estimar o consumo de tempo dos algoritmos de uxo em
redes, por exemplo) foi igualmente ignorada. Finalmente, no foi possvel mencionar
a teoria da complexidade de problemas e a questo P=NP.
75
Bibliograa
[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 emInformtica 2009.
SBC (Soc. Bras. de Computao). PUC-Rio, 2009. ISBN 978-85-87926-54-8. 7
[6] P. Feoloff. Algoritmos de Programao Linear. Internet http://www.ime.usp.
br/~pf/prog-lin/, 1999. 206 pginas. 62
[7] P. Feoloff. Anlise de Algoritmos. Internet http://www.ime.usp.br/~pf/
analise_de_algoritmos/, 2011.
[8] C.G. Fernandes, F.K. Miyazawa, M. Cerioli, and P. Feoloff, editors. Uma Introdu-
o 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. Hromkovi c. Algorithmics for Hard Problems: Introduction to Combinatorial Opti-
mization, 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 Program-
ming. 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. Szwarcter and L. Markenzon. Estruturas de Dados e seus Algoritmos. Livros
Tcnicos e Cientcos, second edition, 1994.
[21] N. Ziviani. Projeto de Algoritmos (com implementaes em Pascal e C). Thomson,
second edition, 2004.
ndice remissivo
x|, 11, 12
,x|, 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-rst 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-rst search, 71
DFS, 71
dgito, 37
dgitos (nmero de), 37
diviso e conquista, 22, 26, 29, 42
ecincia, 10
estrutura recursiva
de um problema, 11, 32, 44, 48, 51
rmeza (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 FEOFILOFF
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
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
sucientemente 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 especco, 55
valor majoritrio, 33
Vazirani, 42
vrtice (de grafo), 59
vetor crescente, 25
vivel, 43, 51, 55
vizinhos (vrtices), 67

Você também pode gostar