Надрукуйте n дивних цифр


12

Дивне число - це число, яке сума правильних дільників перевищує саме число, і жодне підмножище правильних дільників не дорівнює цьому числу.

Приклади:

70 - дивне число, оскільки його правильні дільники (1, 2, 5, 7, 10, 14 і 35) становлять 74, що більше 70, а жодна комбінація цих чисел не дорівнює 70.

18 - це не дивне число, оскільки його належні дільники (1, 2, 3, 4, 6, 9) становлять 25, що більше 18, а 3, 6 та 9 - 18.

Ваше завдання - написати найкоротшу програму, яка вводить через std-будь-яке число n і обчислює та друкує у файл або викреслює перші n дивних номерів з розділенням рядка. Не допускається жорстке кодування відповідей (вибачте, що не вказали це на початку).

Більше прикладів див. На цій сторінці: http://mathworld.wolfram.com/WeirdNumber.html


1
Коли це питання було в пісочниці, я не коментував, що вам слід додати правило "без жорсткого кодування", оскільки воно вже є у слові "обчислити". Я закликаю людей оскаржувати та позначати як невідповіді чи неякісні відповіді, які не намагаються підрахувати результат. ( Відповідна мета дискусія ).
Пітер Тейлор

Відповіді:


2

Mathematica 99 94 87

Проміжки не потрібні. Повільно !:

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

За рахунок кількох знаків це більш швидка версія, яка перевіряє лише парні числа та пропускає кратні 6, які ніколи не дивні:

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

вона все ще занадто повільна для будь-яких корисних цілей. Перші два знаходить за кілька секунд, але стає повільніше і повільніше, оскільки кількість дільників збільшується.


Я поспілкувався з подібним рішенням, використовуючи той факт, що дивні номери не є псевдодосконалими, але ви отримали це набагато гольфіст, ніж я ще встиг. Дуже хороша!
Джонатан Ван Матре

@JonathanVanMatre Дякую :)
Доктор belisarius,

4

Хаскелл - 129

Я впевнений, що тут багато для гольфу, але оскільки конкуренція здається низькою, я зараз кину це.

Не намагайтеся це запустити, але мені вдалося чекати лише двох перших елементів, третій почне займати хвилини.

(%)=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
Це другий раз, коли хтось у Хаскеллі кращий за мене в Sage, чорт: D
yo

2

Python 2.7 (255 байт)

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 байт

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

І ось початковий вихідний код:

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

Ви зауважите, що для виведення цифр потрібен певний час, оскільки він виконує грубу силу перевірки (хоча ви повинні отримати 70 досить швидко).


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}

Версія без гольфу:

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
}

Це займає деякий час через грубу силу.


1

Рубі - 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 With 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}

Дійсно повільно, і я майже впевнений, що є ще місце для гольфу ...


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

вхід:

1000

вихід:

70
836

1

SageMath: 143 131 байт

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

Це навіть більше, навіть не в гольф, у коді все одно не так вже й багато. Найбільше, що ви повинні зробити тест 2*x>=sum(l)спочатку, це дозволить заощадити багато часу на обчислення. Треба розуміти , що maxна булевом є orДругий річ в тому , що w(x)це Falseза дивні числа і Trueдля не країни чисел. Негольована версія:

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

Це ще не все моє рішення, тому що мені довелося просити SO про допомогу в обчисленні суми підмножини, але все інше моє:

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

Довга версія:

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

Наразі він підрахував лише перші два (70 та 836). Я вбив його після цього.


Було б непогано також опублікувати читану версію, тим більше, що ви робите це як однолінійний;)
yo

@tohecz Звичайно, дозвольте мені це відредагувати.

@tohecz Я закінчив.

1

Перл, 173

Дозвольте додати ще одне марне рішення. Це рішення настільки повільне, що він навіть не може вивести нічого, що минає за першим дивним числом. Смію сказати, що це найповільніше з усіх рішень тут.

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

Демо

Той самий код, написаний на Java (з яким мені зручніше), навіть не може розпізнати 2 дивне число (836), і я вже подав номер безпосередньо до способу перевірки (замість того, щоб циклічно перевіряти та перевіряти кожне число).

Суть цього рішення лежить в регулярній виразці:

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

І як встановлено рядок в 3 рази більше числа, яке ми перевіряємо.

Довжина рядка встановлюється в 3 рази більше числа, яке ми перевіряємо i: перші 2 iпризначені для узгодження підсумків факторів, а останній 1 iпризначений для перевірки, чи є число коефіцієнтом i.

(?=(.+)\1{2}$) використовується для фіксації числа, яке ми перевіряємо.

((.+)(?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$))(?=.*(?=\1$)\3+$))+відповідає коефіцієнтам чисельності. Пізніша ітерація буде відповідати меншому фактору, ніж попередня ітерація.

  • Ми можемо бачити, що ці 2 частини (.+)і (?=.*(?=\1$)\3+$)разом вибирають коефіцієнт кількості, що перевіряється.
  • (?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$)) гарантує, що вибраний коефіцієнт менший за кількість, що перевіряється в першій ітерації, і менший за попередній коефіцієнт у наступних ітераціях.

Режекс намагається зіставити якомога більше факторів кількості, що може, в межах 2 i. Але нас не хвилює фактична величина суми дільників, нас цікавить лише чи велика кількість.

Потім 2-й регекс, який є першим регексом з \1{2}$доданим. У результаті регекс гарантує, що сума (деяких) факторів числа, що перевіряється, дорівнює самому числу:

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

Додане обмеження призведе до того, що двигун регулярних викидів здійснюватиме зворотний пошук за всіма можливими підмножинами факторів, тому це буде дуже повільним.


1

Perl, 176 174 байт

$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, а знайдені числа друкуються в STDOUT.

Безгольова версія

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

Обмеження

  • Повільна, груба сила.
  • Кількість дільників на число обмежується "розрядністю" цілих чисел у Perl.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.