Existem muitas soluções para este problema. Serão apresentadas duas. A primeira não recorre a quaisquer variáveis auxiliares nem afecta os valores da variáveis, limitando-se a considerar todos os casos possíveis. A segunda recorre a uma variável auxiliar de modo a simplificar os testes e afecta os valores das variáveis.
A segunda solução pode considerar-se melhor que a primeira porque:
{ (* Pressupostos: *) } { (* Resultado a atingir: *) Deve aparecer escrito qual o maior e qual o mais pequeno de tres valores lidos da entrada. } maior_menor_1 inicio inteiro a, b, c, temp; escrever linha; escrever "Introduza tres valores: "; ler para a, b, c; (* No final "a" guardara' o menor dos valores e "b" guardara' o maior dos valores. *) se a > b: (* Troca "a" com "b" de modo a que "a < b": *) temp <- a; a <- b; b <- temp; fim se; (* Neste instante e' garantido que a <= b. *) (* Se "c > b", entao "c" e' o maior e "a" o mais pequeno, caso contrario temos "c <= b", logo "c" so' "ameaca" "a" (dai a comparacao subsequente com "a"). *) se c > b: b <- c; senao: se c < a: a <- c; fim se; fim se; escrever "Menor: ", a, linha; escrever "Maior: ", b, linha; fim.
{ (* Pressupostos: *) } { (* Resultado a atingir: *) Deve aparecer escrito qual o maior e qual o mais pequeno de tres valores lidos da entrada. } maior_menor_2 inicio inteiro a, b, c; escrever linha; escrever "Introduza tres valores: "; ler para a, b, c; se a >= b: se c >= a: (* c e' o maior e b e' o menor. *) escrever "Maior: ", c, linha, "Menor: ", b, linha; senao: (* a e' o maior. *) escrever "Maior: ", a, linha; se c <= b: (* c e' o menor. *) escrever "Menor: ", c, linha; senao: (* b e' o menor. *) escrever "Menor: ", b, linha; fim se; fim se; senao: se c >= b: (* c e' o maior e a e' o menor. *) escrever "Maior: ", c, linha, "Menor: ", a, linha; senao: (* b e' o maior. *) escrever "Maior: ", b, linha; se c <= a: (* c e' o menor. *) escrever "Menor: ", c, linha; senao: (* a e' o menor. *) escrever "Menor: ", a, linha; fim se; fim se; fim se; fim.
Neste caso procura-se o menor e o maior de vinte valores. Claro que seria possível declarar vinte variáveis e testar todas as possíveis combinações de maior e menor (20 x 19 = 380 !), mas o algoritmo tornar-se-ia demasiado extenso, quase incompreensível e, pior, se se pretendesse alterar de 20 para 30 o número de valores a comparar todo o algoritmo deveria ser alterado. Assim, a melhor solução neste caso é semelhante à pior solução na alínea anterior.
A ideia é ir actualizando duas variáveis, minimo
e maximo
à medida que novos valores são lidos, um
pouco como se fez quando se somaram n valores [Aula 2,
exercício 4.a)]. Com que valor devem ser inicializados minimo
e maximo
? Existem "elementos neutros" das
comparações a fazer? Existem conceptualmente apenas: +infinito
para o menor e -infinito para o maior. A solução então pode
ser inicializar com ... o primeiro valor lido, como aliás se
poderia ter feito no caso da soma.
A única desvantagem deste método é que não é possível saber o menor e o maior valor duma sequência de zero valores, mas isso provavelmente também não faria muito sentido.
{ (* Pressupostos: *) } { (* Resultado a atingir: *) Deve aparecer escrito qual o maior e qual o mais pequeno de vinte valores lidos da entrada. } maior_menor_de_vinte inicio inteiro valor, minimo, maximo; escrever linha; escrever "Introduzir 20 valores:", linha; (* Ler o primeiro valor: *) ler para valor; (* Inicializar "minimo" e "maximo" com o primeiro valor: *) minimo <- valor; maximo <- valor; (* Repetir 19 vezes (20-1) porque um dos valores ja' foi lido: *) repetir 19 vezes: ler para valor; se valor > maximo: maximo <- valor; senao: se valor < minimo: minimo <- valor; fim se; fim se; fim repetir; escrever "Maior: ", maximo, linha, "Menor: ", minimo, linha; fim.
Apresentam-se três alternativas, sucessivamente refinadas. Quais as vantagens e desvantagens relativas? Cumprirão todas o enunciado? Não! Em rigor só a primeira alternativa cumpre o enunciado (que pede explicitamente para serem lidos 20 valores). As alternativas 2 e 3 são apresentadas para exemplificar soluçãos típicas para problemas em que é lícito "curto-circuitar" o ciclo terminando-o prematuramente.
{ (* Pressupostos: *) } { (* Resultado a atingir: *) Deve aparecer escrito se ocorreu o valor 7 alguma vez em 20 valores lidos da entrada. } ocorre_7_1 inicio inteiro valor; logico ocorreu_sete; escrever linha; escrever "Introduzir 20 valores:", linha; (* Inicializar "ocorreu_sete" com "falso": *) ocorreu_sete <- falso; repetir 20 vezes: ler para valor; se valor = 7: ocorreu_sete <- verdadeiro; fim se; fim repetir; escrever "O numero 7 "; se nao ocorreu_sete: escrever "nao "; escrever "ocorreu.", linha; fim.
{ (* Pressupostos: *) } { (* Resultado a atingir: *) Deve aparecer escrito se ocorreu o valor 7 alguma vez em 20 valores lidos da entrada. } ocorre_7_2 inicio inteiro valor, contador; logico ocorreu_sete; escrever linha; escrever "Introduzir 20 valores:", linha; (* Inicializar "contador" com zero: *) contador <- 0; (* Inicializar "ocorreu_sete" com "falso": *) ocorreu_sete <- falso; enquanto contador < 20 e nao ocorreu_sete: ler para valor; se valor = 7: ocorreu_sete <- verdadeiro; fim se; contador <- contador + 1; fim enquanto; escrever "O numero 7 "; se nao ocorreu_sete: escrever "nao "; escrever "ocorreu.", linha; fim.
{ (* Pressupostos: *) } { (* Resultado a atingir: *) Deve aparecer escrito se ocorreu o valor 7 alguma vez em 20 valores lidos da entrada. } ocorre_7_3 inicio inteiro valor, contador; escrever linha; escrever "Introduzir 20 valores:", linha; (* Inicializar "contador" com zero: *) contador <- 0; fazer: ler para valor; contador <- contador + 1; enquanto contador < 20 e valor 7; escrever "O numero 7 "; se valor 7: escrever "nao "; escrever "ocorreu.", linha; fim.
{ (* Pressupostos: *) } { (* Resultado a atingir: *) Deve aparecer escrito quantas vezes ocorreu o valor 7 em 20 valores lidos da entrada. } quantos_7 inicio inteiro valor, quantos; escrever linha; escrever "Introduzir 20 valores:", linha; (* Inicializar "quantos" com o elemento neutro da adicao: *) quantos <- 0; repetir 20 vezes: ler para valor; se valor = 7: quantos <- quantos + 1; fim se; fim repetir; escrever "O numero 7 ocorreu ", quantos, "vezes.", linha; fim.
A solução deste problema é um pouco mais subtil que a
solução da alínea b). Neste caso é necessário manter um
contador de ocorrências e verificar se o valor lido é igual ao maximo
corrente (se o for o número de ocorrências é incrementado).
{ (* Pressupostos: *) } { (* Resultado a atingir: *) Deve aparecer escrito qual o maior de vinte valores lidos da entrada e quantas vezes ocorreu. } maior_de_vinte_e_ocorrencias inicio inteiro valor, maximo, contador; escrever linha; escrever "Introduzir 20 valores:", linha; (* Ler o primeiro valor: *) ler para valor; (* Inicializar "maximo" com o primeiro valor: *) maximo <- valor; (* Inicializar "contador" com um (porque?): *) contador <- 1; (* Repetir 19 vezes (20-1) porque um dos valores ja' foi lido: *) repetir 19 vezes: ler para valor; se valor > maximo: maximo <- valor; contador <- 1; senao: se valor = maximo: contador <- contador + 1; fim se; fim se; fim repetir; escrever "Maior: ", maximo, linha, "Ocorrencias: ", contador, linha; fim.
Neste caso a solução passa por utilizar uma acção cíclica
enquando
(note-se que há uma solução alternativa
com fazer
enquanto
). Mas existe um
problema: se o primeiro valor lido for negativo que fazer?
{ (* Pressupostos: *) } { (* Resultado a atingir: *) Deve aparecer escrito qual o maior dos valores lidos da entrada ate' ao primeiro negativo (exclusive') e quantas vezes ocorreu. } maior_e_ocorrencias_ate_negativo inicio inteiro valor, maximo, contador; escrever linha; escrever "Introduzir valores (terminar com negativo):", linha; (* Ler primeiro valor: *) ler para valor; (* Se o primeiro valor lido e' negativo, a sequencia esta' vazia: *) se valor < 0: escrever "Nao se leu nenhum valor!", linha; senao: (* Porque^ esta atribuicao? *) maximo <- valor; (* Contador e' zero porque dentro do enquanto, e antes de ser lido novo valor, o contador sera' incrementado (ja' que maximo = valor): *) contador <- 0; (* Enquanto "valor" nao for negativo... *) enquanto valor >= 0: (* O valor e' o novo maximo? *) se valor > maximo: maximo <- valor; contador <- 1; senao: (* O valor e' de novo o maximo? *) se valor = maximo: contador <- contador + 1; fim se; fim se; (* Ler proximo valor: *) ler para valor; fim enquanto; escrever "Maior: ", maximo, linha, "Ocorrencias: ", contador, linha; fim se; fim.
Notem-se os seguintes problemas:
{ (* Pressupostos: *) } { (* Resultado a atingir: *) Deve aparecer escrito se uma sequencia de valores lidos da entrada, ate' ao primeiro zero (exclusive'), esta' por ordem crescente. } sequencia_crescente inicio inteiro valor, valor_anterior; escrever linha; escrever "Introduzir valores (terminar com zero):", linha; (* Ler primeiro valor: *) ler para valor; (* Inicializar valor_anterior com valor, pois nao "estraga" o teste de ordem... *) valor_anterior <- valor; (* Enquanto "valor" nao for zero... *) enquanto valor <> 0 e valor >= valor_anterior: valor_anterior <- valor; (* Ler proximo valor: *) ler para valor; fim enquanto; (* * Aqui so' se chega se: * 1. valor = 0 (e todos os valores (se e' que se leu algum!) estavam por * ordem crescente!); * 2. valor 0 e valor < valor_anterior (encontrou-se um valor fora de * ordem). * Por outro lado, se valor_anterior = 0 entao nao ouve valores lidos, * pois de outro modo valor_anterior teria sido atribuido de valor, * sendo forcosamente nao nulo. *) se valor_anterior = 0: escrever "Nao se leu nenhum valor!", linha; senao: escrever "A sequencia "; se valor <> 0: escrever "nao "; fim se; escrever "estava por ordem crescente.", linha; fim se; fim.
Note-se que mais uma vez esta solução viola o enunciado, porque pára no primeiro valor que viole a condição de sequência crescente! Como se poderia corrigir o algoritmo?
{ (* Pressupostos: *) } { (* Resultado a atingir: *) Deve aparecer escrito se uma sequencia de valores lidos da entrada, ate' ao primeiro zero (exclusive'), e' mono'tona. } sequencia_mono'tona inicio inteiro valor, valor_anterior; logico constante, crescente; escrever linha; escrever "Introduzir valores (terminar com zero):", linha; (* Inicializar "constante" ("crescente" nao precisa de ser inicializado porque ainda nao tem significado!): *) constante <- verdadeiro; (* Ler primeiro valor: *) ler para valor; (* Inicializar valor_anterior com valor, pois nao "estraga" o teste de ordem... *) valor_anterior <- valor; (* Enquanto "valor" nao for zero e for coerente com o estado... *) enquanto valor <> 0 e (constante ou (valor >= valor_anterior e crescente) ou (valor <= valor_anterior e nao crescente)): se constante: se valor > valor_anterior: constante <- falso; crescente <- verdadeiro; senao: se valor < valor_anterior: constante <- falso; crescente <- falso; fim se; fim se; fim se; valor_anterior <- valor; (* Ler proximo valor: *) ler para valor; fim enquanto; (* * Aqui so' se chega se: * 1. valor = 0 (e todos os valores (se e' que se leu algum!) estavam por * ordem mono'tona!); * 2. valor 0 e nao constante e nao (valor >= valor_anterior e * crescente) e nao (valor <= valor_anterior e nao crescente), ou seja * se se encontrou um valor fora de ordem. * Por outro lado, se valor_anterior = 0 entao nao ouve valores lidos, * pois de outro modo valor_anterior teria sido atribuido de valor, * sendo forcosamente nao nulo. *) se valor_anterior = 0: escrever "Nao se leu nenhum valor!", linha; senao: escrever "A sequencia "; se valor <> 0: escrever "nao "; fim se; escrever "e' monotona.", linha; se valor = 0: se constante: escrever "E' constante.", linha; senao: se crescente: escrever "E' crescente.", linha; senao: escrever "E' decrescente.", linha; fim se; fim se; fim se; fim se; fim.
Note-se que mais uma vez esta solução viola o enunciado, porque pára no primeiro valor que viole a condição de sequência monótona! Como se poderia corrigir o algoritmo?
O problema fundamental a resolver é saber se um dado valor n é ou não primo. O método mais simples - e menos eficiente! - para resolver este problema é tentar dividir n por todos os valores de 2 a n - 1. Se o resto da divisão for nulo alguma vez, o número não é primo. Se o resto nunca for nulo, o número é primo:
{ (* Pressupostos: *) n > 2 } { (* Resultado a atingir: *) Deve aparecer escrita a seque^ncia dos primos de 2 a n, sendo n lido da entrada. } primeiros_primos inicio inteiro n, valor, divisor; escrever linha; escrever "Primos ate': "; ler para n; (* E' escusado testar o 2, que sabemos ser primo... *) escrever 2, linha; para valor <- 3, n: divisor <- 2; enquanto divisor < valor e valor mod divisor 0: divisor <- divisor + 1; fim enquanto; se divisor = valor: escrever valor, linha; fim se; fim para; fim.
Para além do método sugerido no texto, muitos outros há para acelerar a verificação de se um número é primo. Por exemplo, é claro que se n não é divisível por 2 também não o é por nenhum valor maior que n div 2. Aliás, em geral basta testar com divisores d tais que d^2 <= n!
Se existir algum mecanismo de guardar os números primos conhecidos, então ainda é possível tornar mais eficiente o algoritmo se se verificar que basta testar se n é divisível pelos primos d até d^2 <= n!
A solução seguinte é a mais óbvia, e porventura a menos eficiente:
{ (* Pressupostos: *) a, b > 0 } { (* Resultado a atingir: *) Deve aparecer escrito o mdc de a e b. } mdc_1 inicio inteiro a, b, divisor; escrever linha; escrever "Mdc de: "; ler para a, b; (* Como o mdc nao pode ser maior que o menor dos valores "a" e "b"... *) se a < b: divisor <- a; senao: divisor <- b; fim se; (* Testar divisores desde o menor de "a" e "b" ate' 1: *) enquanto divisor <> 1 e (a mod divisor <> 0 ou b mod divisor <> 0): divisor <- divisor - 1; fim enquanto; escrever divisor, linha; fim.
É fácil provar que se m é o mdc de a e b
(ambos positivos), m também é o mdc de b e a
mod
b. Note-se que a demonstração abaixo
é válida mesmo quando a mod
b =
0, embora nesse caso o mdc seja obviamente b.
Seja m o mdc de a e b. Então, existem c e d tais que:
a = m c
b = m d
Seja r = a mod b e q = a div b. Então a = b q + r.
Ou seja:
m c = m d q + r.
Donde:
r = m (c - d q)
Assim, provou-se que r = a mod b é divisível por m.
Falta apenas provar que m é não só divisor de b e r = a mod b, mas também o maior dos divisores de b e r.
Suponha-se que existe n > m divisor de b e r. Então existem x e y tais que:
b = n x
r = n y
Mas:
q n x + n y = q b + r = a
Por outro lado:
q n x + n y = n (q x + y)
Logo:
a = n (q x + y)
Ou seja, n não só divide b como também divide a! Logo m não é o mdc de a e b, o que é absurdo. Assim, não existe nenhum divisor de b e r maior do que m, ou seja m é o mdc de b e r.
Dados a e b, duas coisas podem acontecer:
mod
b = 0 - neste caso o
mdc é o próprio b. mod
b = d 0 -
neste caso o mdc de a e b é o mesmo
que o de b e d, tendo-se assim reduzido
o problema, pois d é menor que a e b.
Note-se que se a < b então a mod
b é a, mas b mod
a
é menor que a! Assim, há vantagem em calcular o resto
da divisão inteira do valor maior pelo valor menor!
{ (* Pressupostos: *) a, b > 0 } { (* Resultado a atingir: *) Deve aparecer escrito o mdc de a e b. } mdc_2 (* Algoritmo de Euclides. *) inicio inteiro a, b, temp; escrever linha; escrever "Mdc de: "; ler para a, b; enquanto b <> 0; temp <- b; b <- a mod b; a <- temp; (* Ou seja, calculou-se "d = a mod b", e ficou "b" com o valor de "d" e "a" com o valor de "b". Desta forma, a proxima divisao faz-se pelo valor mais baixo ("d")! *) fim enquanto; (* Aqui "b" e' sempre zero, e "a" tem o valor antigo de "b", o tal que conduziu ao resto zero, ou seja, o mdc! *) escrever a, linha; fim.
Faça o traçado com 123 (3 x 41) e 321 (3 x 107), cujo mdc é 3, e com 89 (89) e 144 (2^4 x 3^2), mdc 1, para se convencer de que o algoritmo funciona...
Página
concebida e mantida por Eng. Manuel Menezes de Sequeira (última actualização 2006/07/07) Copyright © 1996-2001 ISCTE |