Qual é a permutação lexicográfica (ie, "ordem alfabética") número 1 milhão do vetor (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)? É isso que o problema quer que respondamos. Considero, claro, que o próprio vetor inicial já seja sua primeira permutação. A segunda é (0, 1, 2, 3, 4, 5, 6, 7, 9, 8).
Escrevi um algoritmo que gera sempre a próxima permutação lexicográfica de um vetor trocando posições de elementos apropriados. Acho que vi na Wikipedia, mas não importa. O importante é entender o mecanismo. :o)
O problema é que, pelo menos em R, a resolução é lenta, foram 51,33 segundos na minha máquina. Deve haver alguma maneira mais inteligente de resolver o problema, ao invés de simplesmente gerar um milhão de permutações. Mas não creio que isso seja grave.
Projeto Euler em R
domingo, 6 de abril de 2014
sábado, 5 de abril de 2014
Problema 23 - Soma não-abundante
Chamamos um número de abundante se a soma de seus divisores próprios for maior que ele mesmo. Por exemplo, os divisores próprios de 24 são 1, 2, 3, 4, 6, 8 e 12 e a soma deles resulta em 36, portanto 24 é um número abundante. Sabe-se que todos os inteiros maiores que 28123 podem ser escritos como a soma de dois números abundantes. O problema pede para que calculemos a soma de todos os números naturais que não podem ser escritos como a soma de dois números abundantes.
Implementei um método de força bruta, primeiro gerando todos os números abundantes até 28123, depois gerando todas as somas destes números, então removendo entradas duplicadas e maiores que 28123 e, por fim, somando os elementos do conjunto complementar com relação à seqüência 1, ..., 28123. Segue:
Se alguém souber de um método melhor, agradeço. Não, eu não sei usar hash tables ou coisas do tipo.
Implementei um método de força bruta, primeiro gerando todos os números abundantes até 28123, depois gerando todas as somas destes números, então removendo entradas duplicadas e maiores que 28123 e, por fim, somando os elementos do conjunto complementar com relação à seqüência 1, ..., 28123. Segue:
Se alguém souber de um método melhor, agradeço. Não, eu não sei usar hash tables ou coisas do tipo.
sexta-feira, 4 de abril de 2014
Problema 22 - Pontuação de nomes
Temos uma lista de nomes num arquivo e a missão de calcular uma pontuação para cada nome, da seguinte maneira:
Não tem segredo. That's it.
- Colocar a lista em ordem alfabética;
- Dar um valor ao nome somando-se as posições de seus caracteres (A = 1, B = 2 etc);
- Finalmente, a pontuação do nome será esse valor multiplicado por sua posição na ordem alfabética.
Pede-se para calcular a soma disso tudo.
A variável global LETTERS contém justamente "A", "B", ..., "Z". Isso facilita muito o processo. Usando a biblioteca stringr fica fácil fazer as manipulações de string necessárias.
quinta-feira, 3 de abril de 2014
Problema 21 - Números amigáveis
Um probleminha muito interessante! Seja d(n) a soma dos divisores próprios de um natural n. Se existirem dois números a e b tais que d(a) = b e d(b) = a, então a e b são chamados de números amigáveis. Pede-se, então, para calcular a soma de todos os números amigáveis abaixo de 10000.
O xis da quetão é, apenas, calcular a soma dos divisores de um dado número.
Código 1:
Código 2:
Desempenhos (respectivamente, método 1 e método 2), para comparação:
O xis da quetão é, apenas, calcular a soma dos divisores de um dado número.
- O primeiro método a ser naturalmente pensado é: dado n, ir testando de 2 até raíz(n) se o candidato é divisor e, caso positivo, somar divisor e (por simetria) o resultado da divisão. Para acelerar, caso o número seja ímpar, testo a partir de 3 indo de 2 em 2. Lembrando, aí, que 1 é sempre divisor próprio e que n obviamente não o é.
- O segundo método foi usar a função divisor (ou função sigma), que como corolário provê a soma dos divisores através da decomposição de n em fatores primos. Aparentemente, um método mais inteligente... Mas, agora, vamos à realidade.
Ao invés de apenas rodar para n = 10.000 (e ter a resposta para o problema proposto), também rodei para n = 100.000 e para n = 1.000.000, a fim de comparar os dois métodos.
Código 1:
Código 2:
Desempenhos (respectivamente, método 1 e método 2), para comparação:
- n = 10.000: 1,28seg contra 9,40seg - tempo 7,3x maior
- n = 100.000: 24,30seg contra 1,77min - tempo 4,4x maior
- n = 1.000.000: 10,93min contra 18,83min - tempo 1,7x maior
quarta-feira, 2 de abril de 2014
Problema 20 - Soma dos dígitos de um fatorial
Neste problema, pede-se para encontrar a soma dos dígitos de 100!, isto é, 1 x 2 x 3 x ... x 99 x 100.
O método lógico/ingênuo (oxímoro?) seria calcular 100! e, então, simplesmente somar os dígitos. Mas não foi como eu fiz: o número é muito grande! Muito grande para o R manipulá-lo adequadamente (é maior que 2^500, inclusive, ou seja, bem maior que 2^31, e tem 158 algarismos). O que fiz, então? Ao invés de apelar para bibliotecas que lidem adequadamente com números arbitrariamente grandes, lancei mão do meu método de se multiplicar/somar números "manualmente", calculando 100! desta maneira.
Tá aí.
O método lógico/ingênuo (oxímoro?) seria calcular 100! e, então, simplesmente somar os dígitos. Mas não foi como eu fiz: o número é muito grande! Muito grande para o R manipulá-lo adequadamente (é maior que 2^500, inclusive, ou seja, bem maior que 2^31, e tem 158 algarismos). O que fiz, então? Ao invés de apelar para bibliotecas que lidem adequadamente com números arbitrariamente grandes, lancei mão do meu método de se multiplicar/somar números "manualmente", calculando 100! desta maneira.
Tá aí.
terça-feira, 1 de abril de 2014
Problema 19 - Contando domingos
Objetivo: contar quantos meses, começando em 01/jan/1901 e terminando em 31/dez/2000, começam num domingo.
Método: uma "trapaça". Gerei todos os dias 01 de todos os meses e, usando a função weekdays do R, contei quantos eram domingos.
Quick and dirty.
Feliz dia da mentira, pessoal.
Método: uma "trapaça". Gerei todos os dias 01 de todos os meses e, usando a função weekdays do R, contei quantos eram domingos.
Quick and dirty.
Feliz dia da mentira, pessoal.
segunda-feira, 31 de março de 2014
Problema 18 - Caminho com soma máxima I
Eis aí um problema interessantíssimo. Leia a descrição. É melhor. :o)
Meu método não foi usar força-bruta. Utilizei, ao contrário, uma abordagem de ir gerando a solução para o menor triângulo (começando da extremidade superior) e, então, ir aumentando até atingir o triângulo completo. Primeiro, salvar o triângulo num arquivo de texto. Depois, agi da seguinte maneira a cada linha do triângulo (tente visualizar olhando para o mesmo):
Engenhoso e eficiente. Tanto que também resolvi o Problema 67 com exatamente o mesmo método, sem tirar nem pôr, em pouco mais que um piscar de olhos. Se fosse usar força bruta, o Problema 67 levaria mais que uma eternidade.
Meu método não foi usar força-bruta. Utilizei, ao contrário, uma abordagem de ir gerando a solução para o menor triângulo (começando da extremidade superior) e, então, ir aumentando até atingir o triângulo completo. Primeiro, salvar o triângulo num arquivo de texto. Depois, agi da seguinte maneira a cada linha do triângulo (tente visualizar olhando para o mesmo):
- Os elementos extremos da esquerda e da direita recebem, respectivamente, o seu próprio valor somado ao extremo correspondente da linha anterior.
- Os outros elementos, os que não são extremos, recebem o seu próprio valor somado ao maior elemento da linha anterior imetidamente à sua esquerda ou direita.
- No final, na última linha, o maior elemento desta será a resposta pedida na descrição do problema.
Engenhoso e eficiente. Tanto que também resolvi o Problema 67 com exatamente o mesmo método, sem tirar nem pôr, em pouco mais que um piscar de olhos. Se fosse usar força bruta, o Problema 67 levaria mais que uma eternidade.
Assinar:
Postagens (Atom)