• Nenhum resultado encontrado

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

No documento Algoritmos e Estruturas de Dados I (páginas 67-77)