打印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
当这个问题出现在沙箱中时,我没有评论您应该添加“无硬编码”规则,因为“计算”一词中已经存在该规则。我鼓励人们投票否决任何不尝试计算结果的答案,并将其标记为“无答案”或“低质量”。(相关的元讨论)。
彼得·泰勒

Answers:


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博士2014年

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
那是Haskell中的某人第二次在我的Sage中比我更好:D
yo'14/

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

真的很慢,我几乎可以肯定还有打高尔夫球的空间...


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'14

@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编写的同一代码(我比较满意)甚至无法识别第二个怪异数字(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+$))+匹配数字的因子。与较早的迭代相比,较新的迭代将匹配较小的因子。

  • 我们可以看到,这两个部分(.+),并(?=.*(?=\1$)\3+$)一起选择数为的因素进行检查。
  • (?=.*(?(2)(?=\2$)\3.+$|(?=\1$)\3.+$)) 确保选择的因子小于第一次迭代中要检查的数目,并且小于后续迭代中先前的因子。

正则表达式尝试在2的范围内匹配尽可能多的数字因子i。但是我们不在乎除数之和的实际值,只在乎数量是否丰富。

然后是第二个正则表达式,这是\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中整数的“位数”。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.