6.5 Repeti¸c˜ oes aninhadas
6.5.2 Fatorial
O problema seguinte ´e bastante relevante neste ponto, pois nos permitir´a uma an´alise sobre a t´ecnica usada para resolvˆe-lo. A t´ecnica b´asica implementa diretamente a defini¸c˜ao de fatorial e usa uma estrutura baseada em um aninhamento triplo: um desvio condicional no escopo de um aninhamento duplo.
Problema: Imprimir o valor do fatorial de todos os n´umeros entre 1 e n, sendo n fornecido pelo usu´ario.
O fatorial de n ´e assim definido:
n=n×(n−1)×(n−2)×. . .×3×2×1
Logo, o c´alculo do fatorial de um n´umero tem complexidade linear com rela¸c˜ao ao tamanho da entrada e pode ser facilmente implementado usando a t´ecnica elementar dos acumuladores, conforme ´e ilustrado na figura 6.18.
program f a t o r i a l ; var i , n, fat : integer; begin
read (n) ;
fat:= 1; (∗ inicializacao do acumulador ∗) i := n;
while i >= 1 do begin
fat:= fat ∗ i ; i f i > 1 then
write ( i ,’x’) else
write ( i ,’= ’) ; i := i − 1;
end;
writeln ( fat ) ; end.
Figura 6.18: Obtendo o fatorial den.
Esta vers˜ao resolve o problema para o c´alculo do fatorial de um ´unico n´umero dado como entrada e portanto n˜ao resolve o enunciado. Por´em, basta colocar este trecho sob o controle de outra repeti¸c˜ao que se obt´em o efeito desejado. A solu¸c˜ao ´e apresentada na figura 6.19.
E verdade que o programa funciona, mas ´´ e extremamente ineficiente e repleto de c´alculos redundantes. De fato, o usu´ario que testou o programa para o valor den = 7 vai perceber que a multiplica¸c˜ao de 2×1 ocorreu 6 vezes, a multiplica¸c˜ao de 3×2 ocorreu 5 vezes, a de 4×6 ocorreu 4 vezes e assim por diante. O programador n˜ao explorou corretamente os c´alculos j´a feitos anteriormente. i
Em outras palavras, o programa pode ficar mais eficiente se for feito como ilustrado na figura 6.20, de maneira que o algoritmo, mais esperto, tem complexidade linear, e n˜ao quadr´atica como na vers˜ao anterior. Interessante observar que a solu¸c˜ao, eficiente, usa apenas uma atribui¸c˜ao no escopo de uma repeti¸c˜ao.
6.5. REPETIC¸ ˜OES ANINHADAS 69
program fatorial1 n ;
var cont , i , n, fat : integer; begin
read (n) ; cont:= 1;
while cont<= n do begin
fat:= 1; (∗ inicializacao do acumulador ∗) i := cont ;
while i>= 1 do begin
fat:= fat ∗ i ; i f i > 1 then
write ( i ,’x’) else
write ( i ,’= ’) ; i := i − 1;
end;
writeln ( fat ) ; cont:= cont + 1;
end;
end.
Figura 6.19: Obtendo v´arios fatoriais.
program fatorial1 n ; var cont , n, fat : integer; begin
read (n) ; cont:= 1;
fat:= 1; (∗ inicializacao do acumulador ∗) while cont<= n do
begin
fat:= fat ∗ cont ;
writeln (’fat(’, cont ,’)= ’, fat ) ; cont:= cont + 1;
end;
end.
Figura 6.20: Otimizando o c´alculo dos fatoriais.
6.6 Exerc´ıcios
1. Dados o primeiro termo e a raz˜ao de uma progress˜ao aritm´etica, determinar a soma dos seus primeiros cinco termos.
2. Ler um inteiro positivo N diferente de zero e calcular a soma: 13+ 23+...+N3. 3. Dados dois n´umeros inteiros positivos determinar o valor da maior potˆencia do primeiro que divide o segundo. Se o primeiro n˜ao divide o segundo, a maior potˆencia ´e definida igual a 1.
4. Dados dois n´umeros reais positivos determinar o quociente inteiro do primeiro pelo segundo usando apenas os operadores aritm´eticos reais.
5. Dado um n´umero real positivo determinar sua parte inteira e sua parte fra-cion´aria usando apenas os operadores aritm´eticos reais.
6. Fazer um programa em Pascal que leia uma sequˆencia de pares de n´umeros inteiros quaisquer, sendo dois inteiros por linha de entrada. A entrada de dados termina quando os dois n´umeros lidos forem nulos. Este par de zeros n˜ao deve ser processado e serve apenas para marcar o t´ermino da entrada de dados.
Para cada par A, B de n´umeros lidos, se B for maior do que A, imprimir a sequˆencia A, A+ 1, . . . , B−1, B. Caso contr´ario, imprimir a sequˆencia B, B + 1, . . . , A−1, A.
Exemplos:
Entrada Saida
4 6 4 5 6
-2 1 -2 -1 0 1
2 -3 2 1 0 -1 -2 -3 0 0
7. Um inteiro positivo N ´e perfeito se for igual a soma de seus divisores positivos diferentes deN.
Exemplo: 6 ´e perfeito pois 1 + 2 + 3 = 6 e 1,2,3 s˜ao todos os divisores positivos de 6 e que s˜ao diferentes de 6.
Fa¸ca um programa emPascal que recebe como entrada um n´umero positivoK e mostre osK primeiros n´umeros perfeitos.
8. Dadas as popula¸c˜oesPA ePBde duas cidades AeB em 2009, e suas respectivas taxas de crescimento anualXA e XB, fa¸ca um programa emPascal que receba estas informa¸c˜oes como entrada e determine:
• se a popula¸c˜ao da cidade de menor popula¸c˜ao ultrapassar´a a de maior popula¸c˜ao;
• e o ano em que isto ocorrer´a.
6.6. EXERC´ICIOS 71 9. Escreva um programa em Pascal para ler uma sequˆencia de n´umeros inteiros, terminada em −1. Para cada n´umero inteiro lido, o programa deve verificar se este n´umero est´a na base bin´aria, ou seja, se ´e composto apenas pelos d´ıgitos 0 e 1. Caso o n´umero esteja na base bin´aria, o programa deve imprimir seu valor na base decimal. Caso contr´ario, deve imprimir uma mensagem indicando que o n´umero n˜ao ´e bin´ario. Ao final do programa deve ser impresso, em formato decimal, o maior n´umero v´alido (bin´ario) da sequˆencia.
Dica: dado o n´umero 10011 em base bin´aria, seu valor correspondente em base decimal ser´a dado por
1.24+ 0.23+ 0.22+ 1.21 + 1.20 = 19 Exemplo:
Entrada: Saida:
10011 19
121 numero nao binario
1010 10
101010101 341
0 0
-1
O maior numero binario foi 341
10. Dado o programa abaixo, mostre o acompanhamento de sua execu¸c˜ao para trˆes valores de entrada (valores pequenos). Em seguida, descreva o que o programa faz, comprovando suas afirma¸c˜oes.
program questao1(input , output) ; var
x : integer; y , m: longint ; begin
read(x) ; y := 0;
m := 1;
while x> 0 do begin
y := y + (xmod 2) ∗m;
x := x div 2;
m := m∗ 10;
end;
writeln(y) end.
11. Considere o seguinte c´odigo fonte escrito em Pascal:
program prova (input , output) ; var
i , j , VAL, N: integer; begin
for i := 1 to 4 do begin
read (VAL) ; writeln (VAL, i ) ; for j:= 3 to 5 do begin
read (VAL) ; N:= VAL + i −j ;
writeln (VAL, j ,N) ; end;
read (VAL) ; end;
end.
Suponha que vocˆe dˆe como entrada de dados uma sequˆencia crescente 1, 2, 3, 4, . . . , na medida em que forem sendo executados os comandos “read”. Qual a sa´ıda que ser´a mostrada na tela do computador?
12. Fa¸ca um programa em Pascal que, dada uma sequˆencia de n´umeros naturais positivos terminada por 0 (zero), imprimir o histograma da sequˆencia dividido em quatro faixas (o histograma ´e a contagem do n´umero de elementos em cada faixa):
• Faixa 1: 1 – 100;
• Faixa 2: 101 – 250;
• Faixa 3: 251 – 20000;
• Faixa 4: acima de 20001.
Exemplo:
Entrada: 347 200 3 32000 400 10 20 25 0 Sa´ıda: Faixa 1: 4
Faixa 2: 1 Faixa 3: 2 Faixa 4: 1
13. Sabe-se que um n´umero da forma n3 ´e igual a soma de n n´umeros ´ımpares consecutivos.
Exemplos:
• 13 = 1
• 23 = 3 + 5
• 33 = 7 + 9 + 11
6.6. EXERC´ICIOS 73
• 43 = 13 + 15 + 17 + 19
DadoM, escreva um program emPascal que determine os ´ımpares consecutivos cuja soma ´e igual a n3 para n assumindo valores de 1 a M.
14. Fa¸ca um programa em Pascal que dado um inteiro positivo n, escreva todos os termos, do primeiro ao n-´esimo, da s´erie abaixo. Vocˆe pode assumir que o usu´ario nunca digita valores menores que 1 para n.
5,6,11,12,17,18,23,24, . . .
15. Fa¸ca um programa em Pascal que, dado dois n´umero naturaismendeterminar, entre todos os pares de n´umeros naturais (x, y) tais que x <=m e y <=n, um par para o qual o valor da express˜aoxy−x2+yseja m´aximo e calcular tamb´em esse m´aximo.
16. Leia do teclado uma sequˆencia de N > 0 n´umeros quaisquer. Para cada valor lido, se ele for positivo, imprimir os primeiros 10 m´ultiplos dele.
Cap´ıtulo 7
Aplica¸ c˜ oes das t´ ecnicas elementares
Neste cap´ıtulo vamos escrever solu¸c˜oes para problemas cujo grau de dificuldade ´e similar aos dos problemas do cap´ıtulo anterior, com o objetivo de fixar conceitos.
Nestes problemas as t´ecnicas devem ser combinadas com inteligˆencia, pios deve-se pensar em como resolver problemas complexos usando-se apenas os elementos b´asicos.
A partir de agora omitiremos os cabe¸calhos dos programas em Pascal.
7.1 N´ umeros de Fibonacci
Esta ´e uma das mais famosas sequˆencias de n´umeros que existe. Trata-se dos n´umeros de Fibonacci1. Esta sequˆencia ´e gerada de modo bastante simples. Os dois primeiros valores s˜ao 1 e 1. Os seguintes s˜ao obtidos pela soma dos dois anteriores. Assim, a sequˆencia de Fibonacci ´e: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, . . .
Problema: Imprimir os primeiros n´umeros da sequˆencia de Fibonacci.
Como gerar e imprimir os elementos desta sequˆencia ´e o nosso desafio. A solu¸c˜ao exige que se guarde sempre os dois ´ultimos elementos gerados, sen˜ao n˜ao ´e poss´ıvel resolver o problema. Observamos que a frase do par´agrafo anterior d´a a dica: “os seguintes s˜ao obtidos pela soma dos dois anteriores”.
Na solu¸c˜ao apresentada na figura 7.1 consideramos duas vari´aveis importantes, uma para armazenar o ´ultimo elemento j´a produzido pelo algoritmo, a outra para guardar o pen´ultimo. Com estes dois, ´e poss´ıvel produzir a soma deles, isto ´e, o pr´oximo elemento.
A atualiza¸c˜ao destas vari´aveis deve ser feita sempre que o pr´oximo elemento for obtido, pois a soma do ´ultimo com o pen´ultimo ´e agora o ´ultimo elemento gerado.
O que era o ´ultimo passa a ser o pen´ultimo. A ordem da atualiza¸c˜ao destes valo-res ´e relevante no c´odigo em fun¸c˜ao do esquema de funcionamento de mem´oria do computador. Trocando-se a ordem dos comandos o algoritmo para de funcionar.
O algoritmo da figura 7.1 ´e normalmente o mais utilizado para este problema, isto ´e, define-se os dois primeiros e depois sucessivamente soma-se os dois ´ultimos e
1Vale a pena ler: http://pt.wikipedia.org/wiki/N´umero de Fibonacci.
75
const max=93; (∗ A partir do 94o estoura a capacidade do tipo qword ∗) begin
ultimo:= 1; (∗ inicializacao das variaveis principais ∗) penultimo:= 1;
writeln (’1 ’,penultimo) ; (∗ imprime os dois primeiros valores ∗) writeln (’2 ’, ultimo) ;
cont:= 3 ; (∗ calcula do terceiro em diante ∗)
while cont<= maxdo begin
soma:= penultimo + ultimo ; writeln (cont , ’ ’,soma) ;
penultimo:= ultimo ; (∗ a ordem destes dois comandos ∗)
ultimo:= soma; (∗ eh relevante no codigo ∗)
cont:= cont + 1;
end;
end.
Figura 7.1: Gerando n´umeros da sequˆencia de Fibonacci.
atualiza-se o ´ultimo como sendo esta soma recentemente gerada e o pen´ultimo como sendo o que era o ´ultimo. Existem v´arios outros que s˜ao apresentados como exerc´ıcios.
Um problema similar mas alternativo a este ´e, por exemplo, saber qual ´e o primeiro n´umero de Fibonacci maior do que um determinado valor. Uma pequena altera¸c˜ao no controle de parada e no local do comando de impress˜ao resolve o novo problema.
Isto ´e apresentado na figura 7.2. A diferen¸ca b´asica ´e que neste caso n˜ao ´e preciso contar os n´umeros, pois o crit´erio de parada ´e diferente. Mas ´e importante observar que a parte da gera¸c˜ao dos n´umeros da sequˆencia n˜ao mudou.
const max=1000;
begin
ultimo:= 1; (∗ inicializacao das variaveis principais ∗) penultimo:= 1;
soma:= penultimo + ultimo ;
while soma<= maxdo (∗ calcula do terceiro em diante ∗) begin
Figura 7.2: Imprimindo o primeiro n´umero de Fibonacci maior do que 1000.
Uma das maiores belezas dos n´umeros de Fibonacci ´e que a raz˜ao entre dois termos consecutivos converge para um n´umero irracional conhecido como n´umero
´
aureo (tamb´em podendo ter outros nomes parecidos). Tamb´em ´e denotado pela letra gregaϕ e ´e aproximadamente 1.6180339887499.
7.2. MAIOR SEGMENTO CRESCENTE 77