Project Euler – Problem 28
Alright!
I have been away for a while as there are too many things happening right now and I have been pretty busy.
Well, this time I will resolve Problem 28 from Projet Euler. For this, I will use mostly a manual method for deducing the formulas and then a small C program to finish the sum for us :)
The problem states:
Starting with the number 1 and moving to the right in a clockwise direction a 5 by 5 spiral is formed as follows:
21 22 23 24 25
20 7 8 9 10
19 6 1 2 11
18 5 4 3 12
17 16 15 14 13It can be verified that the sum of the numbers on the diagonals is 101.
What is the sum of the numbers on the diagonals in a 1001 by 1001 spiral formed in the same way?
According to the problem for this spiral the sum is 101 because: 1 + 3 + 5 + 7 + 9 + 13 + 17 + 21 + 25 = 101
Good! So in order to resolve this problem all we have to do is figure out what are the rules that guide the diagonal numbers.
I have divided this spiral in 4 diagonals:
- Center to right upper corner
- Center to right lower corner
- Center to left lower corner
- Center to left upper corner
If we expand this spiral a a little bit more, we will have:
73 74 75 76 77 78 79 80 81
72 43 44 45 46 47 48 49 50
71 42 21 22 23 24 25 26 51
70 41 20 07 08 09 10 27 52
69 40 19 06 01 02 11 28 53
68 39 18 05 04 03 12 29 54
67 38 17 16 15 14 13 30 55
66 37 36 35 34 33 32 31 56
65 64 63 62 61 60 59 58 57
Based on this we can deduce the formulas that generates each diagonal.
1. Center to right upper corner (1, 9, 25, 49, 81, ...)
For this one, we can see that for each level that expands, we have a squared number. So if we put a little bit of thinking on it, we can come up with the following formula:
Where n is the number of the line counting from the center up (The first line being 0)
You can try it!
2. Center to right lower corner (1, 3, 13, 31, 57, ...)
Comparing the results from the center to right upper corner results, we notice that the value here is the same as that diagonal minus 6*n. So the formula goes:
Where n is the number of the line counting from the center down (The first line being 0)
You can try it!
3. Center to left lower corner (1, 5, 17, 37, 65, ...)
Comparing the results from the center to right upper corner results, we notice that the value here is the same as that diagonal minus 4*n. So the formula goes:
Where n is the number of the line counting from the center down (The first line being 0)
You can also try this one!
4. Center to left upper corner (1, 7, 21, 43, 73, ...)
Comparing the results from the center to right upper corner results, we notice that the value here is the same as that diagonal minus 2*n. So the formula goes:
Where n is the number of the line counting from the center up (The first line being 0)
And once again you can try this one!
Now we need to figure out from what value to what value our 'n' should range. We know the following about our grid:
- When the grid is 3x3, we have 9 (3^2) at the right top corner
- When the grid is 5x5, we have 25 (5^2) at the right top corner
- When the grid is 7x7, we have 49 (7^2) at the right top corner
- When the grid is 9x9, we have 81 (9^2) at the right top corner
- When the grid is 1001x1001, we have 1002001 (1001^2) at the right top corner
Based on this we can conclude that we will have 500 lines up, 500 lines down and one line in the center, each line with 1001 rows.
Our sums should look like this then:
We calculate them all and sum them all together. After this is done, we subtract 3 from the sum because in them all we have added the element in the middle of the grid (1), so we have summed the number 1 four times, and the exercise asks us to sum all the numbers in the diagonals, meaning we should add each one of them only once.
We can than use WolframAlpha to calculate this sum, or just write a simple C code for it:
#include <stdio.h> int main() { int n; unsigned long long sum = 0; for(n = 0; n <= 500; n++) { sum += ((2*n+1)*(2*n+1)); // Same as (2*n+1)^2 sum += ((2*n+1)*(2*n+1)) - 6*n; // Same as (2*n+1)^2 - 6*n sum += ((2*n+1)*(2*n+1)) - 4*n; // Same as (2*n+1)^2 - 4*n sum += ((2*n+1)*(2*n+1)) - 2*n; // Same as (2*n+1)^2 - 2*n } printf("Result is: %llu", sum-3); return 0; }
I will leave it up to the user to execute the above code to get the result, or to calculate the formulas using some tool.
Hope you enjoyed! :)
Project Euler – Problema 1
Ao perguntar a um amigo no IRC sobre uma recomendação de hobby, ele me respondeu 'Matemática!'. Eu tinha em mente um hobby onde não precisasse pensar muito, mas matemática já havia me passado pela mente diversas vezes.
Acabei por arranjar um hobby onde não é preciso pensar muito e resolvi também adicionar a matemática como um hobby. Esse post é para falar sobre este último :)
Faz algum tempo fui apresentado ao 'Project Euler', um site com desafios matemáticos que podem ser resolvidos com ou sem o auxílio de um computador. Decidi que vou tentar resolver os problemas, inicialmente sem o auxílio de um computador (quando possível), e então implementarei uma solução utilizando programação.
O Problema
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below 1000.
Em português:
Se nós listarmos todos os números naturais abaixo de 10 que sejam múltiplos de 3 ou 5, teremos 3, 5, 6 e 9. A soma desses múltiplos é 23.
Encontre a soma de todos os multiplos de 3 ou 5 abaixo de 1000.
A Solução Matemática
A primeira idéia para resolver esse problema é dar uma olhada em parte dos conjuntos formados pelos números menores que 1000 e múltiplos de 3 e de 5
M3 terá um total de 333 elementos (999 / 3)
M5 terá um total de 199 elementos (999 / 5)
Algo para se notar é que em ambos os conjuntos existem números repetidos, como por exemplo {15, 30, 45, 60, ...}, logo se realizarmos a soma dos dois conjuntos teremos duplicidade desses números nos dando a resposta incorreta.
Para eliminar esses números de um dos dois conjuntos, precisamos simplesmente subtrair a soma de todos eles do resultado final e para isso precisamos descobrir quais são todos os números múltiplos de 3 E 5 e aplicar o mesmo procedimento de somatória.
Como descobrir esses números então? Simples! Calcula-se o M.M.C. (mínimo múltiplo comum) de 3 e 5, e encontra-se o conjunto dos múltiplos desse valor encontrado para todos os valores abaixo de 1000.
Temos então o novo conjunto M15:
M15 terá um total de 66 elementos (999 / 15)
M15 então é um subconjunto de M3 e também um subconjunto de M5. (Pode-se dizer que M15 está contido em M3 e em M5).
O problema propõe a soma de todos os números múltiplos de 3 OU 5, então precisamos remover o subconjunto M15 de um dos dois conjuntos (M3 ou M5).
Por quê?
Imagine que o problema pedisse a soma de todos os múltiplos de 3 ou 5 abaixo de 20. Teriamos os seguintes conjuntos:
Se realizarmos a somatória de todos os elementos de M3 e M5 a resposta estará incorreta, pois o valor 15 foi somado duas vezes a resposta final, uma vez na somatória dos elementos de M3 e uma vez na somatória de M5.
A solução então é somar M3 a M5 e subtrair M15, fazendo com que o subconjunto M15 seja removido de um dos dois conjuntos.
Então a equação para resolução do problema é:
Não é muito prático realizarmos essa soma na mão, já que ela é composta de muitos números. Olhando bem para as fórmulas, podemos descrever os conjuntos da seguinte maneira:
- O conjunto M3 é a somatória dos primeiros 333 números múltiplos de 3.
- O conjunto M5 é a somatória dos primeiros 199 números múltiplos de 5.
- O conjunto M15 é a somatória dos primeiros 66 números múltiplos de 15.
Em termos matemáticos:
Se expandirmos a primeira equação, teremos algo como:
Todos os elementos estão sendo multiplicados por 3, logo, pode-se colocar o 3 em evidência e teremos:
Que pode ser representado por:
Esse é um resultado bastante interessante pois foi postulado por Gauss (e várias demonstrações do porque podem ser encontradas aqui) que a somatória dos n primeiros números pode ser escrita da seguinte maneira:
Logo, temos a seguinte equação:
Que pode ser escrita da seguinte maneira:
Isso resulta em: 233168
E está ai então a resolução matemática.
A solução com programação
Solução onde não se usam os conceitos matemáticos apresentados acima:
#include <stdio.h> int main(int argc, char **argv) { int i; int resultado = 0; for(i = 1; i < 1000; i++) { if((i%3 == 0) || (i%5 == 0)) resultado += i; } printf("Resultado: %d\n", resultado); return 0; }
Solução onde os conceitos matemáticos acima são utilizados:
#include <stdio.h> int gauss(int n) { return (n*(n+1))/2; } int main(int argc, char **argv) { int resultado; resultado = (3*gauss(333) + 5*gauss(199)) - 15*gauss(66); printf("Resultado: %d\n", resultado); return 0; }