Imprimer n nombres étranges

12

Un nombre étrange est un nombre dont la somme des diviseurs appropriés est supérieure au nombre lui-même et aucun sous-ensemble de diviseurs appropriés n'est égal à ce nombre.

Exemples:

70 est un nombre étrange car ses diviseurs appropriés (1, 2, 5, 7, 10, 14 et 35) totalisent 74, ce qui est supérieur à 70, et aucune combinaison de ces nombres ne correspond à 70.

18 n'est pas un nombre étrange car ses diviseurs propres (1, 2, 3, 4, 6, 9) totalisent 25, ce qui est supérieur à 18, mais 3, 6 et 9 totalisent 18.

Votre tâche consiste à écrire le programme le plus court qui entre via std-in n'importe quel nombre n et calcule et imprime dans un fichier ou std-out les n premiers nombres étranges avec séparation de nouvelle ligne. Aucun codage en dur des réponses n'est autorisé (désolé de ne pas l'avoir spécifié au début).

Pour plus d'exemples, consultez cette page: http://mathworld.wolfram.com/WeirdNumber.html


la source
1
Lorsque cette question était dans le bac à sable, je n'ai pas dit que vous devriez ajouter une règle "pas de codage en dur" car elle est déjà là dans le mot "calculer". J'encourage les gens à voter et à signaler comme non-réponse ou de mauvaise qualité toutes les réponses qui n'essaient pas de calculer le résultat. ( Méta-discussion pertinente ).
Peter Taylor

Réponses:

2

Mathematica 99 94 87

Espaces non nécessaires. Lent!:

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

Au détriment de quelques caractères, il s'agit d'une version plus rapide qui ne vérifie que les nombres pairs et ignore les multiples 6qui ne sont jamais étranges:

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

c'est encore trop lent pour un but utile. Trouve les deux premiers en quelques secondes mais devient de plus en plus lent à mesure que le nombre de diviseurs augmente.

Dr. belisarius
la source
Je jouais avec une solution similaire exploitant le fait que les nombres étranges ne sont pas pseudoperfect, mais vous l'avez obtenu beaucoup plus golfique que je ne l'avais encore réussi. Très agréable!
Jonathan Van Matre
@JonathanVanMatre Merci :)
Dr. belisarius
4

Haskell - 129

Je suis sûr qu'il y a beaucoup à jouer au golf ici, mais comme la compétition semble faible pour l'instant, je vais y jeter un coup d'œil.

N'essayez pas d'exécuter cela cependant, j'ai réussi à attendre seulement les deux premiers éléments, le troisième commencera à prendre des minutes.

(%)=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
la source
1
C'est la deuxième fois que quelqu'un à Haskell est meilleur que moi à Sage, bon sang: D
yo
2

Python 2.7 (255 octets)

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
Élisée
la source
1

PHP, 267 octets

$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";}

Et voici le code source 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";
}

Vous remarquerez qu'il faut un certain temps pour produire les chiffres car il effectue une vérification par force brute (vous devriez cependant arriver à 70 assez rapidement).

Razvan
la source
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}

Version sans 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
}

Cela prend du temps en raison de la force brute.

Sven Hohenstein
la source
1

Rubis - 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 avec 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}

Vraiment lent et je suis presque sûr qu'il y a encore de la place pour le golf ...

fgp
la source
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

contribution:

1000

production:

70
836
blabla999
la source
1

SageMath: 143 131 octets

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

C'est même pas du golf, il n'y a pas trop de golf de toute façon dans le code. La chose la plus importante est que vous devez faire le test en 2*x>=sum(l)premier, cela économiserait beaucoup de temps de calcul. Il faut comprendre que maxsur les booléens, la ordeuxième chose est que w(x)c'est Falsepour les nombres étranges et Truepour les nombres non étranges. Version non golfée:

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 '
la source
1

C ++ - 458

Ce n'est pas toute ma solution car j'ai dû demander à SO de l'aide pour calculer la somme des sous-ensembles, mais tout le reste est à moi:

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

Version longue:

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

Il n'a actuellement calculé que les deux premiers (70 et 836). Je l'ai tué après ça.


la source
Ce serait bien de publier une version lisible également, d'autant plus que vous le faites en une ligne;)
yo '
@tohecz Bien sûr, permettez-moi de le modifier.
@tohecz J'ai terminé.
1

Perl, 173

Permettez-moi d'ajouter une autre solution inutile. Cette solution est si lente qu'elle ne peut même pas sortir quoi que ce soit après le premier nombre étrange. J'ose dire que c'est la solution la plus lente de toutes ici.

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

Démo

Le même code écrit en Java (avec lequel je suis plus à l'aise) ne peut même pas reconnaître le 2ème numéro bizarre (836), et j'ai déjà alimenté le numéro directement dans la méthode de vérification (au lieu de boucler et de vérifier chaque numéro).

Le cœur de cette solution réside dans l'expression rationnelle:

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

Et comment la chaîne est configurée pour être 3 fois le nombre que nous vérifions.

La longueur de la chaîne est configurée pour être 3 fois le nombre que nous vérifions i: les 2 premiers servent ià faire correspondre la somme des facteurs et le dernier 1 iest réservé pour vérifier si un nombre est un facteur de i.

(?=(.+)\1{2}$) est utilisé pour capturer le nombre que nous vérifions.

((.+)(?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$))(?=.*(?=\1$)\3+$))+correspond aux facteurs du nombre. Une itération ultérieure correspondra à un facteur plus petit qu'une itération antérieure.

  • Nous pouvons voir que ces 2 parties (.+)et (?=.*(?=\1$)\3+$)ensemble sélectionnent un facteur du nombre vérifié.
  • (?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$)) s'assure que le facteur sélectionné est plus petit que le nombre vérifié lors de la première itération, et est plus petit que le facteur précédent dans les itérations suivantes.

L'expression régulière essaie de faire correspondre autant de facteurs du nombre que possible dans la limite de 2 i. Mais nous ne nous soucions pas de la valeur réelle de la somme des diviseurs, nous nous soucions seulement de savoir si le nombre est abondant.

Ensuite, le 2e regex, qui est le premier regex avec \1{2}$ajouté. Par conséquent, l'expression régulière s'assure que la somme de (certains) facteurs du nombre contrôlé est égale au nombre lui-même:

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

La contrainte ajoutée obligera le moteur d'expression régulière à effectuer une recherche de retour arrière sur tous les sous-ensembles possibles de facteurs, donc cela va être extrêmement lent.

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

Perl, 176 174 octets

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

Le nombre de nombres étranges est attendu dans STDIN et les nombres trouvés sont imprimés dans STDOUT.

Version non golfée

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

Limites

  • Lente, force brute.
  • Le nombre de diviseurs pour un nombre est limité au "nombre" d'entiers en Perl.
Heiko Oberdiek
la source