Вывести странные числа

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 Спасибо :)
Доктор Белизарий
4

Haskell - 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)
shiona
источник
1
Это второй раз, когда кто-то в Хаскеле лучше меня в Мудреце, чёрт: 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}

Рубин с 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
blabla999
источник
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

С ++ - 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

Perl, 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. Но мы не заботимся о фактическом значении суммы делителей, мы заботимся только о том, является ли число обильным.

Затем второе регулярное выражение, которое является первым регулярным выражением с \1{2}$добавленным. В результате регулярное выражение проверяет, что сумма (некоторых) факторов проверяемого числа равна самому числу:

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

Добавленное ограничение заставит механизм регулярных выражений выполнять поиск в обратном направлении по всем возможным подмножествам факторов, поэтому он будет очень медленным.

n̴̖̋h̷͉a̷̭̿h̸̡̅ẗ̵̨d̷̰ĥ̷̳
источник
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.
Хайко Обердиек
источник