Drucke n seltsame Zahlen

12

Eine seltsame Zahl ist eine Zahl, bei der die Summe der richtigen Teiler größer ist als die Zahl selbst und bei der keine Teilmenge der richtigen Teiler zu dieser Zahl addiert wird.

Beispiele:

70 ist eine seltsame Zahl, weil ihre richtigen Teiler (1, 2, 5, 7, 10, 14 und 35) 74 ergeben, was größer als 70 ist, und keine Kombination dieser Zahlen 70 ergibt.

18 ist keine seltsame Zahl, weil ihre richtigen Teiler (1, 2, 3, 4, 6, 9) zu 25 summieren, was größer als 18 ist, aber 3, 6 und 9 zu 18 summieren.

Ihre Aufgabe ist es, das kürzeste Programm zu schreiben, das über std-in eine beliebige Anzahl n eingibt und die ersten n seltsamen Zahlen mit Zeilenumbruch berechnet und in eine Datei druckt oder ausgibt. Es ist keine harte Kodierung der Antworten erlaubt (Entschuldigung, dass Sie dies nicht am Anfang angegeben haben).

Weitere Beispiele finden Sie auf dieser Seite: http://mathworld.wolfram.com/WeirdNumber.html


quelle
1
Als diese Frage in der Sandbox war, habe ich nicht kommentiert, dass Sie eine "No Hard-Coding" -Regel hinzufügen sollten, da sie bereits im Wort "Berechnen" enthalten ist. Ich ermutige die Leute, Antworten, die nicht versuchen, das Ergebnis zu berechnen, als nicht beantwortet oder als minderwertig abzustimmen und zu kennzeichnen. ( Relevante Metadiskussion ).
Peter Taylor

Antworten:

2

Mathematica 99 94 87

Leerzeichen werden nicht benötigt. Schleppend!:

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

Auf Kosten einiger Zeichen ist dies eine schnellere Version, die nur gerade Zahlen prüft und ein Vielfaches davon überspringt 6, was niemals seltsam ist:

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

es ist immer noch zu langsam für einen nützlichen Zweck. Findet die ersten beiden in wenigen Sekunden, wird aber mit zunehmender Anzahl von Teilern immer langsamer.

Dr. belisarius
quelle
Ich habe mit einer ähnlichen Lösung herumgespielt, indem ich die Tatsache ausgenutzt habe, dass seltsame Zahlen nicht pseudo-perfekt sind. Sehr schön!
Jonathan Van Matre
@ JonathanVanMatre Vielen Dank :)
Dr. Belisarius
4

Haskell - 129

Ich bin mir sicher, dass es hier viel zu Golfen gibt, aber da die Konkurrenz vorerst gering zu sein scheint, werde ich mich darum kümmern.

Versuchen Sie nicht, dies auszuführen. Ich habe es geschafft, nur die beiden ersten Elemente abzuwarten. Das dritte wird einige Minuten dauern.

(%)=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
quelle
1
Das ist das zweite Mal , wenn jemand in Haskell besser ist als ich in Sage, verdammt: D
yo‘
2

Python 2.7 (255 Byte)

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
Elisha
quelle
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";}

Und hier ist der ursprüngliche Quellcode:

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

Sie werden feststellen, dass die Ausgabe der Zahlen einige Zeit in Anspruch nimmt, da eine Brute-Force-Überprüfung durchgeführt wird (Sie sollten jedoch ziemlich schnell auf 70 kommen).

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

Ungolf-Version:

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
}

Dies kann aufgrund von Brute-Force einige Zeit in Anspruch nehmen.

Sven Hohenstein
quelle
1

Rubin - 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 mit 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}

Wirklich langsam und ich bin mir fast sicher, dass es noch Platz zum Golfen gibt ...

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

Eingang:

1000

Ausgabe:

70
836
blabla999
quelle
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 ist außerdem nicht einmal Golf, es gibt sowieso nicht zu viel im Code, um Golf zu spielen. Das größte Problem ist, dass Sie den Test 2*x>=sum(l)zuerst durchführen sollten, da dies eine Menge Rechenzeit einsparen würde. Man muss erkennen, dass maxauf Booleschen Zahlen das orzweite ist, w(x)was Falsefür seltsame Zahlen und Truefür nicht-seltsame Zahlen gilt. Ungolfed-Version:

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

C ++ - 458

Dies ist nicht meine Lösung, da ich SO um Hilfe bei der Berechnung der Summe der Teilmengen bitten musste, aber alles andere ist meine:

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

Lange Version:

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

Derzeit wurden nur die ersten beiden (70 und 836) berechnet. Ich habe es danach getötet.


quelle
Es wäre schön , eine lesbare Version als auch zu veröffentlichen, vor allem , weil Sie es als Einzeiler machen;)
yo‘
@tohecz Klar, lass es mich bearbeiten.
@tohecz Ich bin fertig.
1

Perl, 173

Lassen Sie mich eine weitere nutzlose Lösung hinzufügen. Diese Lösung ist so langsam, dass sie nicht einmal mehr nach der ersten seltsamen Zahl ausgeben kann. Ich wage zu sagen, es ist hier die langsamste aller Lösungen.

$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

Derselbe in Java geschriebene Code (mit dem ich mich besser auskenne) kann nicht einmal die 2. seltsame Nummer (836) erkennen, und ich habe die Nummer bereits direkt in die Prüfmethode eingegeben (anstatt jede Nummer zu durchlaufen und zu prüfen).

Der Kern dieser Lösung liegt in der Regex:

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

Und wie der String so eingestellt ist, dass er das Dreifache der Zahl ist, die wir überprüfen.

Die Länge des Strings ist so eingestellt, dass sie das Dreifache der Zahl ist, die wir überprüfen i: Die erste 2 idient zur übereinstimmenden Summierung von Faktoren, und die letzte 1 idient zur Überprüfung, ob eine Zahl ein Faktor von ist i.

(?=(.+)\1{2}$) wird verwendet, um die Nummer zu erfassen, die wir überprüfen.

((.+)(?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$))(?=.*(?=\1$)\3+$))+stimmt mit den Faktoren der Zahl überein. Eine spätere Iteration entspricht einem kleineren Faktor als eine frühere Iteration.

  • Wir können sehen, dass diese 2 Teile (.+)und (?=.*(?=\1$)\3+$)zusammen einen Faktor der zu überprüfenden Zahl auswählen.
  • (?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$)) Stellt sicher, dass der ausgewählte Faktor kleiner als die Zahl ist, die in der ersten Iteration überprüft wird, und kleiner als der vorherige Faktor in nachfolgenden Iterationen.

Der reguläre Ausdruck versucht, so viele Faktoren der Zahl wie möglich innerhalb der Grenze von 2 zuzuordnen i . Aber wir kümmern uns nicht um den tatsächlichen Wert der Summe der Teiler, wir kümmern uns nur darum, ob die Anzahl reichlich vorhanden ist.

Dann wird die 2. Regex, die die erste mit Regex ist, \1{2}$hinzugefügt. Infolgedessen stellt der reguläre Ausdruck sicher, dass die Summe (einiger) Faktoren der zu überprüfenden Zahl mit der Zahl selbst übereinstimmt:

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

Die hinzugefügte Einschränkung veranlasst die Regex-Engine, eine Rückverfolgungssuche für alle möglichen Teilmengen von Faktoren durchzuführen, sodass sie extrem langsam sein wird.

n̴̖̋h̴̖̋ã̷͉h̷̭̿d̷̰̀ĥ̷̳
quelle
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++}

Die Anzahl der seltsamen Zahlen wird in STDIN erwartet und die gefundenen Zahlen werden in STDOUT ausgegeben.

Ungolfed-Version

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

Einschränkungen

  • Langsame, rohe Gewalt.
  • Die Anzahl der Teiler für eine Zahl ist auf die "Bitness" von Ganzzahlen in Perl beschränkt.
Heiko Oberdiek
quelle