Tuhaf numaralar yazdır


12

Garip bir sayı, uygun bölenlerin toplamının sayının kendisinden daha büyük olduğu ve uygun bölenlerin hiçbir alt kümesinin bu sayıya karşılık gelmediği bir sayıdır.

Örnekler:

70, garip bir sayıdır, çünkü uygun bölücüler (1, 2, 5, 7, 10, 14 ve 35) 74'e eşittir, bu sayı 70'ten büyüktür ve bu sayıların hiçbiri 70'e eşit değildir.

18 tuhaf bir sayı değildir, çünkü uygun bölücüler (1, 2, 3, 4, 6, 9) 25'e eşittir, bu sayı 18'den büyüktür, ancak 3, 6 ve 9 toplamı 18'dir.

Senin görevin std-in herhangi bir n sayısı ile girer ve bir dosyaya hesaplar ve yazdırır veya satır sonu ile ilk n garip sayıları std-out en kısa program yazmaktır . Cevapların kesin olarak kodlanmasına izin verilmez (başlangıçta bunu belirtmediğim için üzgünüm).

Daha fazla örnek için bu sayfaya bakın: http://mathworld.wolfram.com/WeirdNumber.html


1
Bu soru sanal alanda olduğunda, "sabit kodlama" kuralı eklemeniz gerektiğini söylemedim çünkü zaten "hesapla" sözcüğünde var. İnsanları, sonucu hesaplamaya çalışmayan yanıtları yanıtlamama veya düşük kaliteli olarak indirmeye ve işaretlemeye teşvik ediyorum. ( İlgili meta tartışma ).
Peter Taylor

Yanıtlar:


2

Mathematica 99 94 87

Boşluk gerekmez. Yavaş!:

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

Birkaç karakter pahasına bu, sadece sayıları kontrol 6eden ve asla garip olmayan katlarını atlayan daha hızlı bir sürümdür :

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

herhangi bir yararlı amaç için hala çok yavaş. İlk ikisini birkaç saniye içinde bulur, ancak bölen sayısı arttıkça yavaşlar ve yavaşlar.


Garip sayıların sahte olmadığı gerçeğini kullanan benzer bir çözümle uğraşıyordum, ancak henüz başaramadığımdan çok daha golfçü aldın. Çok hoş!
Jonathan Van Matre


4

Haskell - 129

Eminim burada golf yapılacak çok şey var, ancak rekabet şu an için düşük göründüğü için bunu atacağım.

Bunu çalıştırmayı denemeyin, sadece ilk iki elemanı beklemeyi başardım, üçüncüsü dakikalar almaya başlayacak.

(%)=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)

1
Bu, Haskell'deki birisinin Sage'de benden daha iyi olduğu, lanet olsun: D
yo

2

Python 2.7 (255 bayt)

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

1

PHP, 267 bayt

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

Ve işte orijinal kaynak kodu:

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

Bir kaba kuvvet doğrulaması yaparken sayıların çıkmasının biraz zaman alacağını göreceksiniz (yine de 70'e hızlı bir şekilde ulaşmalısınız).


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}

Golfsiz sürüm:

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
}

Bu kaba kuvvet nedeniyle biraz zaman alır.


1

Yakut - 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}

ActiveSupport ile Ruby - 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}

Gerçekten yavaş ve neredeyse golf için yer olduğundan eminim ...


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

giriş:

1000

çıktı:

70
836

1

SageMath: 143 131 bayt

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

Dahası, golf bile değil, yine de kodda golf için çok fazla değil. En büyük şey, önce testi yapmanız gerektiğidir 2*x>=sum(l), çok fazla hesaplama süresi kazandıracaktır. Bir fark vardır maxboolelerde üzerindedir orİkinci şey olmasıdır w(x)olduğu Falsegarip sayılar için ve Trueolmayan garip sayılar için. Ungolfed sürümü:

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

1

C ++ - 458

Alt kümelerin toplamını hesaplamak için SO'dan istemek zorunda olduğum için tüm çözümüm bu değil, ama her şey benim:

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

Uzun versiyon:

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

Şu anda sadece ilk ikisini hesaplamıştır (70 ve 836). Ondan sonra öldürdüm.


Özellikle tek katmanlı olarak yaptığınız için okunabilir bir sürüm de yayınlamak güzel olurdu;)
yo

@tohecz Elbette, düzenleyeyim.

@tohecz İşim bitti.

1

Perl, 173

Başka bir işe yaramaz çözüm ekleyeyim. Bu çözüm o kadar yavaş ki, ilk garip sayıyı aşan bir şey bile üretemiyor. Buradaki tüm çözümlerin en yavaşı olduğunu söylemeye cesaret ediyorum.

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

gösteri

Java ile yazılmış aynı kod (ki daha rahatım) 2. garip numarayı bile (836) tanıyamıyor ve numarayı zaten doğrudan kontrol yöntemine (döngü ve her sayıyı kontrol etmek yerine) besledim.

Bu çözümün özü normal ifadede yatmaktadır:

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

Ve dizenin nasıl kontrol ettiğimiz sayının 3 katı olacağı.

Dizenin uzunluğu, kontrol ettiğimiz sayının 3 katı olacak şekilde ayarlanır i: ilk 2 i, faktörlerin toplamını eşleştirmek içindir ve son 1 i, bir sayının faktör olup olmadığını kontrol etmek için ayrılmıştır i.

(?=(.+)\1{2}$) kontrol ettiğimiz sayıyı yakalamak için kullanılır.

((.+)(?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$))(?=.*(?=\1$)\3+$))+sayının faktörlerini eşleştirir. Daha sonraki yineleme, önceki yinelemeden daha küçük bir faktörle eşleşecektir.

  • Bu 2 parçanın (.+)ve (?=.*(?=\1$)\3+$)birlikte kontrol edilen sayının bir faktörünü seçtiğini görebiliriz .
  • (?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$)) seçilen faktörün ilk yinelemede kontrol edilen sayıdan daha küçük ve sonraki yinelemelerde önceki faktörden daha küçük olmasını sağlar.

Normal ifade, sayının 2 sınırı dahilinde olabildiğince çok faktörü eşleştirmeye çalışır i. Ancak bölenlerin toplamının gerçek değerini umursamıyoruz, sadece sayının bol olup olmadığını önemsiyoruz.

Sonra \1{2}$eklenen ilk normal ifade olan 2. normal ifade . Sonuç olarak, normal ifade, kontrol edilen sayının (bazı) faktörlerinin toplamının sayının kendisine eşit olmasını sağlar:

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

Eklenen kısıtlama, normal ifade motorunun olası tüm faktör alt kümelerinde geri izleme araması yapmasına neden olacaktır, bu nedenle son derece yavaş olacaktır.


1

Perl, 176 174 bayt

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

STDIN'de garip sayıların sayısı bekleniyor ve bulunan sayılar STDOUT'a yazdırılıyor.

Ungolfed sürümü

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

Sınırlamalar

  • Yavaş, kaba kuvvet.
  • Bir sayının bölen sayısı, Perl'deki tamsayıların "biti" ile sınırlıdır.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.