在此生成的二进制矩阵中打印特定值


14

假设我们以这种方式在MN^2 -> {0, 1}N1代替0)开始定义一个无限矩阵:

  • M(1, 1)= 0

  • 对于每个x > 1M(x, 1)= 1if x是素数,0否则。

  • 对于每一个y > 1M(1, y)=的y中日长期Thue-Morse sequence

  • 对于每个x, y > 1M(x, y)= M(x, y-1) + M(x-1, y) mod 2

16x16矩阵的左上部分看起来像(具有x行和y列):

0 1 1 0 1 0 0 1 1 0 0 1 0 1 1 0
1 0 1 1 0 0 0 1 0 0 0 1 1 0 1 1
1 1 0 1 1 1 1 0 0 0 0 1 0 0 1 0
0 1 1 0 1 0 1 1 1 1 1 0 0 0 1 1
1 0 1 1 0 0 1 0 1 0 1 1 1 1 0 1
0 0 1 0 0 0 1 1 0 0 1 0 1 0 0 1
1 1 0 0 0 0 1 0 0 0 1 1 0 0 0 1
0 1 1 1 1 1 0 0 0 0 1 0 0 0 0 1
0 1 0 1 0 1 1 1 1 1 0 0 0 0 0 1
0 1 1 0 0 1 0 1 0 1 1 1 1 1 1 0
1 0 1 1 1 0 0 1 1 0 1 0 1 0 1 1
0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 1
1 1 0 0 1 0 1 1 0 1 1 1 0 1 1 0
0 1 1 1 0 0 1 0 0 1 0 1 1 0 1 1
0 1 0 1 1 1 0 0 0 1 1 0 1 1 0 1
0 1 1 0 1 0 0 0 0 1 0 0 1 0 0 1

您的任务是构建一个程序,该程序将尽可能准确地评估此矩阵中任意条目的值。

您的程序将使用两个整数,x并且y以您选择的任何形式作为输入,然后返回M(x, y),它们将为01

您的代码可以用任何语言编写,但源代码大小不得超过64 KB(65,536字节)或总内存使用量不得超过2 MB(2,097,152字节)。您的程序必须从空内存开始(即,它不能从其他地方加载数据)并针对每个输入独立运行(即,它可能不存储多次运行的通用数据)。您的程序还必须能够8192x8192在合理的时间内评估左上角的所有条目。

在左上角正确评估最多条目的程序8192 x 8192将是赢家,而较短的代码将成为平局。


我可能会在稍后将测试用例更新为稍微更优雅的内容,因此请继续测试直到我再次编辑问题。
乔·Z。2014年

@mbuettner是的,确实如此。
2014年

1
我看不到我们如何需要一个用于“准确性”的新标签。这只是[代码挑战]。请首先通过meta来运行新的挑战类型创意(我们从[代码拖曳]中学到了一件事)。
门把手

^注意。我将删除该标签。
Joe Z.

1
@TheDoctor并不少见。接受的答案会随时间变化。
2014年

Answers:


9

J- 42 38个字符

相当快,100%准确,并且完全在内存限制内。

([{+2&(~:/@#:@#@],~:/\,(p:>:)&#)0:)&<:

策略如下:我们将计算该矩阵的连续反对角线,执行成对的XOR进行移动,并将当前的Thue-Morse和质数位添加到末端。然后,当我们到达对角线时,将其从对角线中拉出。

爆炸解释:

(                                 )&<:  NB. decrement each of x and y
     &(                        )        NB. apply the following function...
   +                                    NB. ... (x-1)+(y-1) times...
                                0:      NB. ... starting with a zero:
    2             ~:/\                  NB.   pairwise XOR on the argument
                      ,(p:>:)&#         NB.   append prime bit (is 1+length prime?)
       ~:/@#:@#@],                      NB.   prepend TM bit (XOR of binary)
 [{                                     NB. take the x-th bit (at index x-1)

此动词的用法x m y用于问题中指定的M(x,y),m动词在哪里。

   5 ([{+2&(~:/@#:@#@],~:/\,(p:>:)&#)0:)&<: 8
0
   m =: ([{+2&(~:/@#:@#@],~:/\,(p:>:)&#)0:)&<:
   1+i.16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   m/~ 1+i.16
0 1 1 0 1 0 0 1 1 0 0 1 0 1 1 0
1 0 1 1 0 0 0 1 0 0 0 1 1 0 1 1
1 1 0 1 1 1 1 0 0 0 0 1 0 0 1 0
0 1 1 0 1 0 1 1 1 1 1 0 0 0 1 1
1 0 1 1 0 0 1 0 1 0 1 1 1 1 0 1
0 0 1 0 0 0 1 1 0 0 1 0 1 0 0 1
1 1 0 0 0 0 1 0 0 0 1 1 0 0 0 1
0 1 1 1 1 1 0 0 0 0 1 0 0 0 0 1
0 1 0 1 0 1 1 1 1 1 0 0 0 0 0 1
0 1 1 0 0 1 0 1 0 1 1 1 1 1 1 0
1 0 1 1 1 0 0 1 1 0 1 0 1 0 1 1
0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 1
1 1 0 0 1 0 1 1 0 1 1 1 0 1 1 0
0 1 1 1 0 0 1 0 0 1 0 1 1 0 1 1
0 1 0 1 1 1 0 0 0 1 1 0 1 1 0 1
0 1 1 0 1 0 0 0 0 1 0 0 1 0 0 1

为了节省击键次数,我们不会尝试告诉我们是否仍然需要更多素数或Thue-Morse位,因此我们计算整个反对角线以获得所需的位。但是,8192 m 8192在我适中的笔记本电脑上,运行时间仍少于0.07 s,约100 KiB。


6

数学- 100%的准确度, 223个 193 189字节

f=(r=Array[0&,Max@##];For[s=2,s<=#+#2,++s,For[i=Max[1,s-#2],i<=Min[s-1,#],++i,j=s-i;r[[j]]=Which[i==1,PrimeQ@j,j==1,OddQ@Total@IntegerDigits[i-1,2],0<1,Xor@@r[[j-1;;j]]]]];If[r[[#2]],1,0])&

这是一个清晰的版本:

f[x_,y_] := (
   r = Array[0 &, Max[x,y]];
   For[s = 2, s <= x + y, ++s,
    For[
     i = Max[1, s - y],
     i <= Min[s - 1, x],
     ++i,

     j = s - i;
     r[[j]] = Which[
       i == 1,
       PrimeQ@j,
       j == 1,
       OddQ@Total@IntegerDigits[i - 1, 2],
       0 < 1,
       r[[j - 1]]~Xor~r[[j]]
       ]
     ]
    ];
   If[r[[y]], 1, 0]
   );

我基本上是沿着常数的对角线进行预计算 x+y

特征:

  • 没错
  • 它在 O(x*y)
  • f[8192,8192]大约需要400秒。我认为还有改进的空间(也许RotateLeft可以替换内部循环)。
  • 它仅max(x,y)在内存中使用多达中间结果的一个数组。因此,算法本身不必使用超过32k(假设32位整数)的值(再加上Mathematica使用的任何值)。实际上,Mathematica在我的系统上单独使用了31M,但这可以正常工作:

    MemoryConstrained[f[8192, 8192], 2^21]
    

好吧,看来您明白了。我会在将来做难度的,虽然:P
乔Z.

嗯,在其中一项更改中,我一定弄错了运行时性能。内部循环仍称为O(x*y)时间,但是总的执行时间比这快。我不太确定发生了什么。如果某些Mathematica Guru可以启发我,那么循环中的哪个操作不是O(1)很有帮助!:)(当然,PrimeQTotal@IntegerDigits都没有,但我已经在他们从一开始就和他们只叫O(y)O(x)分别次)
马丁安德

3

Matlab:100%准确度,120个字符,不合理的执行时间

function z=M(x,y)
if y==1 z=(x>1)*isprime(x);elseif x==1 z=mod(sum(dec2bin(y-1)-48),2);else z=xor(M(x,y-1),M(x-1,y));end

使用方法:

> M(4,4)
ans =
      0
> M(1, 9)
ans =
      1

1
现在是问题所在,您可以实际运行该程序并进行测试吗?
Joe Z.

如果你不能跑步M(8192, 8192),我不能接受。
2014年

@JoeZ这是M代码,您可以在Matlab或Octave中运行它。
intx13 2014年

@JoeZ它将精确计算M(8192,8192)。挑战没有说明要完成的时间;)
intx13 2014年

1
@JoeZ看起来M(20,20)花费的时间比我愿意等待的时间长。但是,嘿,这是“准确的”!:P
intx13 2014年

2

Python,192个字符

100%的精度,在我的机器上约10秒内即可计算出M(8192,8192)。

R=range
def M(X,Y):
 X+=1;c=[1]*X;r=[0]
 while len(r)<Y:r+=[i^1 for i in r]
 for i in R(2,X):
  if c[i]:
   for j in R(i+i,X,i):c[j]=0
  r[0]=c[i]
  for i in R(1,Y):r[i]^=r[i-1]
 return r[Y-1]

0

Haskell-261字节-100%-1MB-我认为它不会很快结束

m 16 16with 大约需要10秒钟-O2,但是正如我已经写的那样,尽管存在这个问题,我仍然可以显示它:

m x y=if n x y then 1 else 0 where n x 1=b x;n 1 y=(a!!13)!!(y-1);n x y=(n x (y-1))`f`(n(x-1)y)
f True False=True
f False True=True
f _ _=False
a=[False]:map step a where step a=a++map not a
b x=x`elem`takeWhile(<=x)e
e=c [2..]where c(p:s)=p:c[x|x<-s,x`mod`p>0]

也许一些好的Haskeller能够对其进行优化?

m' x y = if m x y then 1 else 0
    where
        m x 1 = isPrime x
        m 1 y = morse' y
        m x y = (m x (y-1)) `xor` (m (x-1) y)

xor True False = True
xor False True = True
xor _ _ = False

morse' x = (morse !! 13) !! (x-1)
morse = [False] : map step morse where step a = a ++ map not a

isPrime x = x `elem` takeWhile (<=x) primes
primes :: [Integer]
primes = sieve [2..] where sieve (p:xs) = p : sieve [x|x <- xs, x `mod` p > 0]

main = putStrLn $ show $ m' 16 16

我认为算法本身是有缺陷的。无论如何,您可以做很多事情来打高尔夫球。大多是多余的括号,但也f p|p=not|0<1=id应该更好。另外,请尝试morse = False : concat $ iterate [True] (\a -> a ++ map not a)增加懒惰度。我不知道它将如何影响性能。
2015年

另外,还可以打高尔夫球True0<1False0>1
2015年

0

Perl,137岁

不是要“赢” :-),但是由于这里还没有Perl并且无论如何都编写了代码,所以就在这里。

sub f{($n,$m)=@_;@a=0;@a=(@a,map{0+!$_}@a)while@a<$n;for$k(2..$m){$p=0;O:{$k%$_?1:last O for 2..sqrt$k;$p=1}$p=$a[$_]^=$p for 1..$n-1}$p}

调用需要几秒钟 print f(8192,8192),,将单行矩阵存储在内存中(8192个整数(标量)数组),整个Perl过程约为3.5 Mb。我尝试使用字符串而不是数组(使用正则表达式或使用substr进行访问)来执行此操作,它占用较少的内存,并且可以进一步使用,但是运行速度慢得多。

缩进:

sub f{
    ($n,$m)=@_;
    @a=0;                                  # @a will be current line.
    @a=(@a,map{0+!$_}@a)while@a<$n;        # Fill it with Thue-Morse sequence.
    for$k(2..$m){                          # Repeat until required line number.
        $p=0;                              # Find out if current line number 
        O:{                                # is a prime.
            $k%$_?1:last O for 2..sqrt$k;
            $p=1                           # Store result (0 or 1) in $p.
        }
        $p=$a[$_]^=$p for 1..$n-1          # XOR previous value in current position
    }                                      # with $p and store in $p.
    $p                                     # Return $p.
}

0

哈斯克尔(223)

g n=div(filter(>=n)(iterate(*2)1)!!0)2
1%1=0>1
1%n=not$1%(n-g n)
n%1=and[rem n x>0|x<-[2..n-1]]
a%b=g[0<1]where g s|foldr seq(0>1)s=0<1|n==a+b=s!!(b-1)|0<1=g$n%1:zipWith x s(tail s)++[1%n]where n=length s+1
x p|p=not|0<1=id

这具有快速的运行时间(使用5.7秒-O3)。内存尚未检查,尽管应该是线性的。

这使用了前面看到的对角线算法。

就速度而言,最重要的是对角线算法-O3|foldr seq(0>1)s=0<1保护,这使列表更加严格。其他所有事情的执行效率都很低-素数检查是通过检查所有较小的数字进行除法来进行的,莫尔斯序列的元素不断地被重新计算。但它仍然足够快:-)。

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.