Imprime n números raros

12

Un número extraño es un número en el que la suma de divisores propios es mayor que el número mismo y ningún subconjunto de divisores propios suma a ese número.

Ejemplos:

70 es un número extraño porque sus divisores propios (1, 2, 5, 7, 10, 14 y 35) suman 74, que es mayor que 70, y ninguna combinación de estos números suma 70.

18 no es un número extraño porque sus divisores propios (1, 2, 3, 4, 6, 9) suman 25, que es mayor que 18, pero 3, 6 y 9 suman 18.

Su tarea es escribir el programa más corto que ingresa a través de cualquier número n estándar y calcula e imprime en un archivo o elimina los primeros n números raros con separación de línea nueva. No se permite la codificación de las respuestas (perdón por no especificar esto al principio).

Para obtener más ejemplos, consulte esta página: http://mathworld.wolfram.com/WeirdNumber.html


fuente
1
Cuando esta pregunta estaba en la caja de arena, no comenté que debería agregar una regla de "no codificación rígida" porque ya está allí en la palabra "calcular". Animo a las personas a que den un voto negativo y marquen como respuestas que no son una respuesta o de baja calidad las que no intentan calcular el resultado. ( Meta discusión relevante ).
Peter Taylor

Respuestas:

2

Mathematica 99 94 87

Espacios no necesarios. ¡Lento!:

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

A expensas de unos pocos caracteres, esta es una versión más rápida que verifica solo números pares y omite múltiplos 6que nunca son raros:

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

todavía es demasiado lento para cualquier propósito útil. Encuentra los dos primeros en unos segundos, pero se vuelve más y más lento a medida que aumenta el número de divisores.

Dr. belisario
fuente
Estaba jugando con una solución similar explotando el hecho de que los números extraños no son pseudoperfectos, pero lo obtuviste mucho más golfista de lo que todavía había logrado. ¡Muy agradable!
Jonathan Van Matre
@JonathanVanMatre Gracias :)
Dr. belisarius
4

Haskell - 129

Estoy seguro de que hay mucho para jugar golf aquí, pero como la competencia parece baja por ahora, voy a tirar esto.

Sin embargo, no intente ejecutar esto, logré esperar solo los dos primeros elementos, el tercero comenzará a tomar 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
fuente
1
Esa es la segunda vez que alguien en Haskell es mejor que yo en Sage, maldición: 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
Elíseo
fuente
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";}

Y aquí está el código fuente 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";
}

Notarás que lleva un tiempo generar los números, ya que realiza una verificación de fuerza bruta (aunque deberías llegar a 70 bastante rápido).

Razvan
fuente
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}

Versión sin golf:

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
}

Esto lleva algún tiempo debido a la fuerza bruta.

Sven Hohenstein
fuente
1

Rubí - 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 con 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}

Muy lento y estoy casi seguro de que todavía hay espacio para jugar al golf ...

fgp
fuente
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

salida:

70
836
blabla999
fuente
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

Es más, ni siquiera golf, no hay demasiado golf de todos modos en el código. Lo más importante es que 2*x>=sum(l)primero debe hacer la prueba , le ahorraría mucho tiempo de cálculo. Uno tiene que darse cuenta de que maxen booleanos lo orsegundo es que w(x)es Falsepara números extraños y Truepara números no extraños. Versión sin golf:

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'
fuente
1

C ++ - 458

Esta no es toda mi solución, ya que tuve que pedir ayuda a SO para calcular la suma de los subconjuntos, pero todo lo demás es mío:

#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++;}}

Versión larga:

#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++;
    }
}

Actualmente solo ha calculado los dos primeros (70 y 836). Lo maté después de eso.


fuente
Sería bueno publicar una versión legible también, especialmente porque lo haces como una sola línea;)
yo '
@tohecz Claro, déjame editarlo.
@tohecz ya terminé.
1

Perl, 173

Déjame agregar otra solución inútil. Esta solución es tan lenta que ni siquiera puede mostrar nada más allá del primer número extraño. Me atrevo a decir que es la solución más lenta de todas aquí.

$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++}

Manifestación

El mismo código escrito en Java (con el que me siento más cómodo) ni siquiera puede reconocer el segundo número extraño (836), y ya he alimentado el número directamente al método de verificación (en lugar de recorrer y verificar cada número).

El núcleo de esta solución se encuentra en la expresión regular:

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

Y cómo se configura la cadena para que sea 3 veces el número que estamos comprobando.

La longitud de la cadena está configurada para que sea 3 veces el número que estamos verificando i: los primeros 2 ison para la suma de factores coincidentes y el último 1 iestá reservado para verificar si un número es un factor de i.

(?=(.+)\1{2}$) se utiliza para capturar el número que estamos verificando.

((.+)(?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$))(?=.*(?=\1$)\3+$))+coincide con los factores del número. La iteración posterior coincidirá con un factor más pequeño que una iteración anterior.

  • Podemos ver que estas 2 partes (.+)y (?=.*(?=\1$)\3+$)juntas seleccionan un factor del número que se verifica.
  • (?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$)) se asegura de que el factor seleccionado sea más pequeño que el número que se verifica en la primera iteración, y es más pequeño que el factor anterior en las iteraciones posteriores.

La expresión regular intenta hacer coincidir tantos factores del número como sea posible dentro del límite de 2 i. Pero no nos importa el valor real de la suma de divisores, solo nos importa si el número es abundante.

Luego, la segunda expresión regular, que es la primera expresión regular con \1{2}$agregado. Como resultado, la expresión regular se asegura de que la suma de (algunos) factores del número que se verifica sea igual al número mismo:

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

La restricción añadida hará que el motor de expresiones regulares realice una búsqueda de retroceso en todos los subconjuntos posibles de factores, por lo que será extremadamente lento.

n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
fuente
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++}

Se espera el número de números extraños en STDIN y los números encontrados se imprimen en STDOUT.

Versión sin golf

#!/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__

Limitaciones

  • Lenta, fuerza bruta.
  • El recuento de divisores para un número se limita a la "bitness" de los enteros en Perl.
Heiko Oberdiek
fuente