O primeiro passo é fazer uma simulação na mão, por exemplo para dez armários:
Na figura acima, os * indicam os toques nos armários e os X indicam os armários que ficaram abertos no final. Deste exercício dá para intuir algumas coisas:
- Se olharmos as colunas (armários) dá apra perceber que neste processo estamos tocando neles conforme os seus divisores.
- Os armários que ficaram abertos correspondem aos "quadrados perfeitos" (quadrados exatos de um número inteiro).
- A distância entre os ármários abertos vai crescendo conforme os números impares ou, se preferir, entre os armários abertos temos um número de armários fechados que correspondem aos números pares. (Isto talvez não seja tão evidente com apenas 10 armários).
Vamos pensar um pouco em como os divisores se distribuem e como podemos pareá-los. Se um número é divisível por a, ele será também divisível por n/a. Se um número n é divisível por a <= sqrst(n), é fácil perceber que n/a >= sqrt(n), onde sqrt é a raiz quadrada. Em outras palavras, os fatores se distribuem equilibradamente em torno da raiz quadrada. Por exemplo, considerando os fatores do número 6, podemos agrupá-los em (1,6) e (2,3). Já para o número 4, teremos o par (1, 4) e a raiz (2) isolada. Este raciocínio confirma a nossa hipótese de que os armários que ficam abertos são os quadrados perfeitos, e sugere a seguinte solução:
void Solucao1 (int n)E quanto à nossa intuição sobre a distãncia entre as portas abertas? Uma técnica muito útil quando queremos otimizar um algoritmo é fazer os cálculos de forma incremental, calculando o resultado seguinte a partir do anterior. No nosso caso, a fórmula para calcular (n+1)2 a partir de n2:
{
int i, max;
max = (int) floor(sqrt (n));
for (i = 1; i <= max; i++)
printf ("%d ", i*i);
}
(n+1)2 = n2 + 2*n + 1
O que sugere uma segunda solução:
void Solucao2 (int n)Esta segunda solução tem as vantagens de eliminar a raiz quadrada e a multiplicação (que ficou reduziada a um shift). Este tipo de técnica (cálculo incremental) é muito útil em processadores mais "fracos" como os que eram usados nos primeiros computadores pessoais ou presentes na maioria dos microcontroladores.
{
int i, num;
for (i = 1, num = 1; num <= n; num = num + (i << 1) + 1, i++)
printf ("%d ", num);
}
Nenhum comentário:
Postar um comentário