Imprimir n números estranhos

12

Um número estranho é um número em que a soma dos divisores adequados é maior que o próprio número e nenhum subconjunto de divisores apropriados soma esse número.

Exemplos:

70 é um número estranho, porque seus divisores adequados (1, 2, 5, 7, 10, 14 e 35) somam 74, que é maior que 70, e nenhuma combinação desses números soma 70.

18 não é um número estranho porque seus divisores adequados (1, 2, 3, 4, 6, 9) somam 25, o que é maior que 18, mas 3, 6 e 9 somam 18.

Sua tarefa é escrever o programa mais curto que insira std-in qualquer número ne calcula e imprime em um arquivo ou std-out os primeiros n números estranhos com separação de nova linha. Nenhuma codificação embutida das respostas é permitida (desculpe por não especificar isso no início).

Para mais exemplos, consulte esta página: http://mathworld.wolfram.com/WeirdNumber.html


fonte
1
Quando esta pergunta estava na sandbox, não comentei que você deveria adicionar uma regra "sem codificação", porque ela já existe na palavra "calcular". Encorajo as pessoas a votar e sinalizar como não resposta ou de baixa qualidade as respostas que não tentam calcular o resultado. ( Meta discussão relevante ).
Peter Taylor

Respostas:

2

Mathematica 99 94 87

Espaços não necessários. Lento!:

j = i = 0;
While[j<#, i++; If[Union@Sign[Tr /@ Subsets@Most@Divisors@i-i]=={-1, 1}, j++; Print@i]]&

À custa de alguns caracteres, esta é uma versão mais rápida que verifica apenas números pares e ignora múltiplos 6que nunca são estranhos:

j = i = 0;
While[j < #, 
      i += 2; If[Mod[i, 6] != 0 && Union@Sign[Tr /@ Subsets@Most@Divisors@i - i] == {-1, 1}, 
                 j++; Print@i]] &@3

ainda é muito lento para qualquer finalidade útil. Localiza os dois primeiros em alguns segundos, mas fica cada vez mais lento à medida que o número de divisores aumenta.

Dr. belisarius
fonte
Eu estava brincando com uma solução semelhante, explorando o fato de que números estranhos não são pseudoperfeitos, mas você conseguiu muito mais golfismo do que eu já havia conseguido. Muito agradável!
Jonathan Van Matre
@JonathanVanMatre Thank you :)
Dr. belisarius
4

Haskell - 129

Tenho certeza de que há muito para jogar aqui, mas como a competição parece baixa, por enquanto, vou jogar isso.

Não tente executar isso, porém, consegui esperar apenas os dois primeiros elementos; o terceiro começará a levar minutos.

(%)=filter
w n=take n$e%[1..]
e x=let d=((==0).mod x)%[1..x-1]in sum d>x&&all((/=x).sum)(i d)
i[]=[[]]
i(y:z)=map(y:)(i z)++(i z)
shiona
fonte
1
Essa é a segunda vez que alguém em Haskell é melhor do que eu em Sage, caramba: D
yo '
2

Python 2.7 (255 bytes)

import itertools as t
a=int(raw_input())
n=1
while a>0:
    d=[i for i in range(1,n/2+1) if not n%i]
    if all([n not in map(sum,t.combinations(d,i)) for i in range(len(d))]+[sum(d)>n]):
        print n
        a-=1
    n+=1
Eliseu
fonte
1

PHP, 267 bytes

$n=$x=0;while($n<$argv[1]){$x++;for($i=1,$s=0,$d=array();$i<$x;$i++){if($x%$i){continue;}$s+=$i;$d[]=$i;}if($s<$x){continue;}$t=pow(2,$m=count($d));for($i=0;$i<$t;$i++){for($j=0,$s=0;$j<$m;$j++){if(pow(2,$j)&$i){$s+=$d[$j];}}if($s==$x){continue 2;}}$n++;print"$x\n";}

E aqui está o código fonte original:

$n = 0;
$x = 0;

while ($n < $argv[1]) {
    $x++;

    for ($i = 1, $sum = 0, $divisors = array(); $i < $x; $i++) {
        if ($x % $i) {
            continue;
        }

        $sum += $i;
        $divisors[] = $i;
    }

    if ($sum < $x) {
        continue;
    }

    $num = count($divisors);
    $total = pow(2, $num);

    for ($i = 0; $i < $total; $i++) {  
        for ($j = 0, $sum = 0; $j < $num; $j++) { 
            if (pow(2, $j) & $i) {
                $sum += $divisors[$j];
            }
        }

        if ($sum == $x) {
            continue 2;
        }
    }

    print "$x\n";
}

Você notará que leva algum tempo para exibir os números enquanto realiza uma verificação de força bruta (você deve chegar a 70 rapidamente).

Razvan
fonte
1

R, 164

r=0;x=1;n=scan();while(r<n){i=which(!x%%(2:x-1));if(sum(i)-1&&!any(unlist(lapply(2:sum(i|T),function(o)colSums(combn(i,o))==x)))&sum(i)>x){r=r+1;cat(x,"\n")};x=x+1}

Versão sem golfe:

r = 0
x = 1
n = scan()
while(r < n) {
  i = which(!x %% (2:x - 1))
  if( sum(i) - 1 &&
       !any(unlist(lapply(2:sum(i | T),
                          function(o) colSums(combn(i, o)) == x))) &
       sum(i) > x
     ){ r = r + 1
        cat(x, "\n")
  }
  x = x + 1
}

Isso leva algum tempo devido à força bruta.

Sven Hohenstein
fonte
1

Ruby - 152

x=2;gets.to_i.times{x+=1 while((a=(1..x/2).find_all{|y|x%y==0}).reduce(:+)<=x||(1..a.size).any?{|b|a.combination(b).any?{|c|c.reduce(:+)==x}});p x;x+=1}

Ruby com ActiveSupport - 138

x=2;gets.to_i.times{x+=1 while((a=(1..x/2).find_all{|y|x%y==0}).sum<=x||(1..a.size).any?{|b|a.combination(b).any?{|c|c.sum==x}});p x;x+=1}

Muito lento e tenho quase certeza de que ainda há espaço para jogar golfe ...

fgp
fonte
1

Smalltalk, 143

((1to:(Integer readFrom:Stdin))reject:[:n||d|d:=(1to:n//2)select:[:d|(n\\d)=0].d sum<n or:[(PowerSet for:d)contains:[:s|s sum=n]]])map:#printCR

entrada:

1000

resultado:

70
836
blabla999
fonte
1

SageMath: 143 131 bytes

x=1
def w():
 l=x.divisors()
 return 2*x>=sum(l)or max(2*x==sum(i)for i in subsets(l))
while n:
 while w():x+=1
 print x;n-=1;x+=1

É mais ou menos nem mesmo jogado, não há muito para jogar de qualquer maneira no código. O mais importante é que você deve fazer o teste 2*x>=sum(l)primeiro, pois isso pouparia muito tempo de computação. É preciso perceber que, maxem booleanos, a orsegunda coisa é que w(x)é Falsepara números estranhos e Truepara números não estranhos. Versão não destruída:

def w(x) :
 Divisors = x.divisors()
 return 2*x >= sum(Divisors) or max ( sum(SubS) == 2*x for SubS in subsets(Divisors) )

x=1

for k in xrange(n) :
 while w(x) : x += 1
 print x
 x += 1
yo '
fonte
1

C ++ - 458

Esta não é toda a minha solução, pois tive que pedir ajuda ao SO para calcular a soma dos subconjuntos, mas todo o resto é meu:

#include<iostream>
#include<vector>
using namespace std;
#define v vector<int>
#define r return
#define c const_iterator
v x(int i){v d;for(int k=1;k<i;k++)if(i%k==0)d.push_back(k);r d;}bool u(v::c i,v::c e,int s){if(s==0)r 0;if(i==e)r 1;r u(i+1,e,s-*i)&u(i+1,e,s);}bool t(v&d,int i){bool b=u(d.begin(),d.end(),i);if(b)cout<<i<<endl;r b;}int main(){v d;int n;cin>>n;for(int i=2,j=0;j<n;i++){d=x(i);int l=0;for(int k=0;k<d.size();k++)l+=d[k];if(l>i)if(t(d,i))j++;}}

Versão longa:

#include<iostream>
#include<vector>
using namespace std;

vector<int> divisors(int i) {

    vector<int> divs;
    for(int k = 1; k < i; k++)
        if(i%k==0)
            divs.push_back(k);
    return divs;
}

bool u(vector<int>::const_iterator vi, vector<int>::const_iterator end, int s) {

    if(s == 0) return 0;
    if(vi == end) return 1;
    return u(vi + 1, end, s - *vi) & u(vi + 1, end, s);
}

bool t(vector<int>&d, int i) {

    bool b = u(d.begin(), d.end(), i);
    if(b) cout<< i << endl;
    return b;
}

int main() {

    vector<int> divs;
    int n;
    cin>>n;

    for(int i = 2, j = 0; j < n; i++) {
        divs = divisors(i);

        int sum_divs = 0;
        for(int k = 0; k < divs.size(); k++)
            sum_divs += divs[k];

        if(sum_divs > i)
            if(t(divs, i))
                j++;
    }
}

No momento, calculou apenas os dois primeiros (70 e 836). Eu matei depois disso.


fonte
Seria bom publicar uma versão legível também, especialmente desde que você a faça como uma linha;)
yo '
@tohecz Claro, deixe-me editá-lo.
@tohecz Estou pronto.
1

Perl, 173

Deixe-me adicionar outra solução inútil. Essa solução é tão lenta que nem consegue produzir nada além do primeiro número estranho. Ouso dizer que é a solução mais lenta de todas aqui.

$n=<>;$i=2;while($n){$b=qr/^(?=(.+)\1{2}$)((.+)(?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$))(?=.*(?=\1$)\3+$))+/;$_='x'x3x$i;if(/$b/&&($+[0]>$i)&&!/$b\1{2}$/){print"$i\n";$n--}$i++}

Demo

O mesmo código escrito em Java (com o qual me sinto mais confortável) não consegue nem reconhecer o segundo número estranho (836), e eu já alimentei o número diretamente no método de verificação (em vez de repetir e verificar todos os números).

O núcleo desta solução está no regex:

^(?=(.+)\1{2}$)((.+)(?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$))(?=.*(?=\1$)\3+$))+

E como a string é configurada para ser 3 vezes o número que estamos verificando.

O comprimento da string é configurado para ser 3 vezes o número que estamos verificando i: os 2 primeiros isão para somar os fatores e o último 1 ié reservado para verificar se um número é um fator dei .

(?=(.+)\1{2}$) é usado para capturar o número que estamos verificando.

((.+)(?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$))(?=.*(?=\1$)\3+$))+corresponde aos fatores do número. A iteração posterior corresponderá a um fator menor que a iteração anterior.

  • Podemos ver que essas duas partes (.+)e (?=.*(?=\1$)\3+$)juntas selecionam um fator do número que está sendo verificado.
  • (?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$)) garante que o fator selecionado seja menor que o número verificado na primeira iteração e menor que o fator anterior nas iterações subseqüentes.

A regex tenta corresponder ao maior número possível de fatores dentro do limite de 2 i . Mas não nos importamos com o valor real da soma dos divisores, apenas nos importamos se o número é abundante.

Em seguida, o segundo regex, que é o primeiro regex \1{2}$adicionado. Como resultado, o regex garante que a soma de (alguns) fatores do número que está sendo verificado seja igual ao próprio número:

^(?=(.+)\1{2}$)((.+)(?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$))(?=.*(?=\1$)\3+$))+\1{2}$

A restrição adicionada fará com que o mecanismo regex execute uma pesquisa de retorno em todos os subconjuntos possíveis de fatores, por isso será extremamente lento.

n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
fonte
1

Perl, 176 174 bytes

$n=<>;$i=9;X:while($n){@d=grep{!($i%$_)}1..$i-1;$l=0;map{$a=$_;$s=0;$s+=$d[$_]for grep{2**$_&$a}0..@d-1;$i++,next X if$s==$i;$l=1 if$s>$i}0..2**@d-1;$n--,print$i,$/if$l;$i++}

O número de números estranhos é esperado em STDIN e os números encontrados são impressos em STDOUT.

Versão ungolfed

#!/usr/bin/env perl
use strict;
$^W=1;

# read number from STDIN
my $n=<>;
# $i is the loop variable that is tested for weirdness
my $i=9; # better start point is 70, the smallest weird number
# $n is the count of numbers to find
X: while ($n) {
    # find divisors and put them in array @divisors
    my @divisors = grep{ !($i % $_) } 1 .. $i-1; # better: 1 .. int sqrt $i
    # $large remembers, if we have found a divisor sum greater than the number
    my $large = 0;
    # looping through all subsets. The subset of divisors is encoded as
    # bit mask for the divisors array.
    map {
        my $subset = $_;
        # calculate the sum for the current subset of divisors
        my $sum = 0;
        map { $sum += $divisors[$_] }
            grep { 2**$_ & $subset }
                0 .. @divisors-1;
        # try next number, if the current number is pseudoperfect
        $i++, next X if $sum == $i; # better: $i+=2 to skip even numbers
        $large = 1 if $sum > $i;
    } 0 .. 2**@divisors - 1;
    # print weird number, if we have found one
    $n--, print "$i\n" if $large;
    $i++; # better: $i+=2 to skip even numbers
}
__END__

Limitações

  • Força lenta e bruta.
  • A contagem de divisores para um número é limitada à "testemunha" de números inteiros em Perl.
Heiko Oberdiek
fonte