Stampa un valore specifico in questa matrice binaria generata


14

Supponiamo di definire una matrice infinita M, su N^2 -> {0, 1}(da dove Ninizia 1invece che 0) in questo modo:

  • M(1, 1)= 0.

  • Per ogni x > 1, M(x, 1)= 1if xè primo, e 0altrimenti.

  • Per ogni y > 1, M(1, y)= il yesimo termine in Thue-Morse sequence.

  • Per ogni x, y > 1, M(x, y)= M(x, y-1) + M(x-1, y) mod 2.

La 16x16sezione in alto a sinistra di questa matrice assomiglia (con xessere righe ed yessere colonne):

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

Il tuo compito è costruire un programma che valuti il ​​valore di una voce arbitraria in questa matrice nel modo più accurato possibile.

Il tuo programma prenderà due numeri interi xe ycome input, in qualsiasi forma tu scelga, e restituirà M(x, y), che sarà 0o 1.

Il codice può essere scritto in qualsiasi lingua, ma non deve superare 64 kilobyte (65.536 byte) di dimensioni del codice sorgente o 2 MB (2.097.152 byte) di utilizzo della memoria totale. Il programma deve iniziare con memoria vuota (ovvero non può caricare dati da qualche altra parte) ed essere eseguito in modo indipendente per ciascun input (ovvero, potrebbe non memorizzare dati comuni per più esecuzioni). Il programma deve inoltre essere in grado di valutare tutte le voci nel 8192x8192riquadro in alto a sinistra in un periodo di tempo ragionevole.

Il programma che valuterà correttamente la maggior parte delle voci nel 8192 x 8192riquadro in alto a sinistra sarà il vincitore, con un codice più breve che fungerà da pareggio.


Probabilmente aggiornerò il caso di test con qualcosa di leggermente più elegante in un momento, quindi resisti con il test fino a quando non modifico nuovamente la domanda.
Joe Z.

@mbuettner Sì, lo fa.
Joe Z.

1
Non riesco a vedere come abbiamo bisogno di un nuovo tag per "accuratezza". Questa è solo una [sfida del codice]. Esegui prima le nuove idee per i generi di sfida tramite meta (c'è una cosa che abbiamo imparato da [code-trolling]).
Maniglia della porta

^ Notato. Rimuoverò quel tag.
Joe Z.

1
@TheDoctor Non è troppo raro. La risposta accettata cambia nel tempo.
Joe Z.

Risposte:


9

J - 42 38 caratteri

Abbastanza veloce, preciso al 100% e ben all'interno dei vincoli di memoria.

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

La strategia è la seguente: calcoleremo i successivi antidiagonali di questa matrice, eseguendo un XOR a coppie per spostarsi lungo e aggiungendo i bit Thue-Morse e prime primi alle estremità. Quindi estraiamo la cifra richiesta dall'antidiagonale quando ci arriviamo.

Spiegazione per esplosione:

(                                 )&<:  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)

L'uso di questo verbo è x m yper M (x, y) come specificato nella domanda, dov'è mil verbo.

   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

Per salvare le sequenze di tasti non cerchiamo di dire se abbiamo ancora bisogno di più bit primi o di martedì, quindi calcoliamo l'intera antidiagonale per ottenere il bit che vogliamo. Tuttavia, 8192 m 8192funziona ancora in meno di 0,07 se circa 100 KiB sul mio laptop modesto.


6

Mathematica - Precisione al 100%, 223 193 189 byte

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])&

Ecco una versione leggibile:

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]
   );

Fondamentalmente ho pre-calcolato lungo diagonali di costante x+y.

Caratteristiche:

  • È preciso.
  • Funziona dentro O(x*y).
  • f[8192,8192]dura circa 400 secondi. Suppongo che ci sono margini di miglioramento (forse RotateLeftpotrebbe sostituire il ciclo interno).
  • Utilizza solo un array di max(x,y)risultati fino a intermedi in memoria. Quindi non è necessario utilizzare più di circa 32k (assumendo numeri interi a 32 bit) per l'algoritmo stesso (in più, qualunque cosa Mathematica usi). Infatti, Mathematica utilizza 31M da sola sul mio sistema, ma questo funziona senza problemi:

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

Beh, sembra che tu l'abbia capito. Ne farò di più difficili in futuro, però: P
Joe Z.

Hm, in una delle modifiche devo aver rovinato le prestazioni di runtime. Il ciclo interno viene ancora chiamato O(x*y)tempi, ma il tempo totale di esecuzione aumenta più rapidamente di quello. Non sono sicuro di cosa stia succedendo. Se qualche Guru di Mathematica potesse illuminarmi, quale operazione nel ciclo non è O(1)quella sarebbe molto utile! :) (beh, PrimeQe Total@IntegerDigitsnon lo sono, ma li ho avuti lì dall'inizio, e hanno chiamato solo O(y)e O(x)volte rispettivamente)
Martin Ender

3

Matlab: precisione al 100%, 120 caratteri, tempo di esecuzione irragionevole

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

Usare:

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

1
Ora ecco la domanda, puoi davvero eseguire questo programma e testarlo?
Joe Z.

Se non puoi correre M(8192, 8192), non posso prenderlo.
Joe Z.

@JoeZ È un codice M, puoi eseguirlo in Matlab o Octave.
intx13

@JoeZ Calcola con precisione M (8192, 8192). La sfida non diceva nulla del tempo per completare;)
intx13

1
@JoeZ bene sembra che M (20,20) impieghi più tempo di quanto io sia disposto ad aspettare. Ma hey, è "preciso"! : P
intx13

2

Python, 192 caratteri

Precisione al 100%, calcola M (8192,8192) in ~ 10 secondi sulla mia macchina.

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 byte - 100% - 1 MB - Non credo che finirà presto

Ci vogliono circa 10 secondi per m 16 16con -O2, ma come ho scritto comunque posso mostrarlo nonostante questo problema:

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]

Forse un buon Haskeller è in grado di ottimizzarlo?

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

penso che l'algoritmo stesso sia difettoso. comunque, ci sono molte cose che puoi fare per giocare a golf. per lo più parentesi extra, ma f p|p=not|0<1=iddovrebbe anche essere migliore. prova anche a usarlo morse = False : concat $ iterate [True] (\a -> a ++ map not a)per aumentare la pigrizia. Mi chiedo come influenzerà le prestazioni.
orgoglioso haskeller il

inoltre, puoi giocare Truea golf da 0<1e Falseverso 0>1.
orgoglioso haskeller il

0

Perl, 137

Per non "vincere" :-), ma dato che non esiste ancora un Perl e che il codice è stato scritto comunque, eccolo qui.

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}

Richiede diversi secondi se chiamato print f(8192,8192), memorizza una singola riga di matrice in memoria (array di 8192 numeri interi (scalari)), circa 3,5 Mb intero processo Perl. Ho provato a farlo con string invece che con array (o con regexps o accedendo con substr), occupa meno memoria e può essere ulteriormente giocato, ma funziona molto più lentamente.

rientrato:

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

Haskell, 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

questo ha un tempo di esecuzione rapido (5,7 secondi con -O3). la memoria non è stata ancora verificata, sebbene dovrebbe essere lineare.

questo utilizza l'algoritmo diagonale visto qui prima.

per quanto riguarda la velocità, le uniche cose che contano sono l'algoritmo diagonale -O3e la |foldr seq(0>1)s=0<1guardia, che rende l'elenco rigoroso. tutto il resto viene implementato in modo piuttosto inefficiente - il controllo di base viene eseguito controllando tutti i numeri minori per la divisione, gli elementi della sequenza Morse vengono costantemente calcolati. ma è ancora abbastanza veloce :-).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.