Primes da espiral de Ulam


17

A espiral de Ulam é um tópico verdadeiramente fascinante, mas intrigante, em matemática. Como ele funciona em detalhes pode ser encontrado aqui , mas um breve resumo pode ser explicado da seguinte forma:

Começo escrevendo um, depois escrevo dois à direita. Acima dos dois, escrevo três e, à esquerda, escrevo quatro. Eu continuo esse padrão de circular em torno de 1 (e qualquer número entre eu e 1) infinitamente (ou até que seja ordenado que pare), formando um padrão em espiral. (veja o exemplo abaixo)

O objetivo

Crie um programa que aceite n (sempre será um número ímpar maior que zero) como uma entrada correlacionada com o número de linhas e, em seguida, imprima os valores dos números primos linha por linha da espiral do Ulam. A formatação pode ser de qualquer forma, mas deve ser legível por humanos e óbvia.

Por exemplo, dada a entrada 3, seu programa deve produzir 5,3,2,7, porque 3 linhas produzem a seguinte espiral:

5 4 3 <-- first row has the primes 5 and 3
6 1 2 <-- second row has the prime 2
7 8 9 <-- third row has the prime 7

Como este é um código de golfe, a resposta com o menor número de bytes vence (não importa quão ineficiente)! As brechas padrão não são aceitáveis.


É permitida uma vírgula à direita? Ou melhor ainda, espaço separado, por exemplo, `` 5 3 2 7 '' `
Tom Carpenter

5
Contanto que seja legível por humanos e possa me dizer os primos, fique à vontade.
Addison Crump

Respostas:


8

Pitão, 20 bytes

f}TPTsuC+R=hZ_GtyQ]]

Experimente online: Demonstração

Este código gera toda a espiral do Ulam, conecta todas as linhas e filtros para números primos.

Explicação:

f}TPTsuC+R=hZ_GtyQ]]   implicit: Z = 0
      u           ]]   reduce, start with G = [[]]
               tyQ     for H in [0, 1, ..., 2*input-2] do:
             _G           reverse the order of the lines
        +R=hZ             append Z + 1 at the end of each line, 
                          updating Z each time with the new value Z + 1
       C                  update G with the transposed of ^
                       this gives the Ulam's spiral
     s                 combine all lines to a big list of numbers
f                      filter for numbers T, which satisfy:
 }TPT                    T appears in the prime-factorization of T
                         (<==> T is prime)

6

MATLAB, 48

a=fliplr(spiral(input(''))');disp(a(isprime(a)))

Basicamente, isso cria uma espiral do tamanho necessário (solicitado pelo usuário) e, em seguida, organiza-a para que apareça na ordem correta das linhas. Isso é armazenado em a. Em seguida, ele exibe todos os valores em que são primos.

Como você disse em qualquer formato legível, salvei um byte e fui para a saída padrão de disp () que é (no seu caso de teste, n = 3):

 5
 3
 2
 7

Como um bônus adicional, isso funciona para qualquer n> 0, incluindo números pares. Por exemplo, a saída para n = 10 é:

97
61
59
37
31
89
67
17
13
 5
 3
29
19
 2
11
53
41
 7
71
23
43
47
83
73
79

11
Muito agradável! É bom saber que spiralfunção é #
Luis Mendo

6

CJam, 42 33 bytes

Xali(2*{_W%zY@,Y+:Y,>a+}*e_{mp},`

Experimente online

A versão mais recente inclui melhorias substanciais sugeridas pelo @Martin.

O método para construir a espiral é, em cada etapa, girar a matriz que temos até agora em 90 graus e adicionar uma linha com números adicionais. Isto é repetido(n / 2) * 4 vezes.

Os valores na matriz resultante são então filtrados por serem primos.

Explicação:

Xa    Push initial matrix [1].
li    Get input and convert to int.
(2*   Calculate 2*(n-1), which is the number of rotations and row additions needed.
{     Start rotation loop.
  _     Copy current matrix for getting number of rows later.
  W%    Reverse the order of the rows...
  z     ... and transpose the matrix. The combination produces a 90 degree rotation.
  Y     Get next value from variable Y (which is default initialized to 2).
  @,    Rotate previous matrix to top, and get number of rows. This is the number
        of columns after the 90 degree rotation, meaning that it's the length of
        the row to be added.
  Y+    Add first value to row length to get end value.
  :Y    Save it in Y. This will be the first value for next added row.
  ,     Create list of values up to end value.
  >     Slice off values up to start value, leaving only the new values to be added.
  a+    Wrap the new row and add it to matrix.
}*    End of rotation loop.
e_    Flatten matrix into list.
{mp}, Filter list for primes.
`     Convert list to string for output.

Pode 2/4*ser substituído por 2*, ou você o deixou de propósito?
ETHproductions

@ETHproductions Isso não é equivalente, porque é uma divisão inteira. Por exemplo, para a entrada 3, o resultado precisa ser 4. Na verdade, agora que penso nisso, acredito que há um byte a ser salvo. (2*deve estar correto.
Reto Koradi 10/10

5

Mathematica 223

Isso apropria o código de Kuba para uma espiral de Ulam. É por isso que estou enviando como um wiki da comunidade. Eu apenas joguei golfe e selecionei os números primos, listados pela linha em que residem.

r=Range;i=Insert;t=Transpose;s@n_:=#~Select~PrimeQ&/@Nest[With[{d=Length@#,l=#[[-1,-1]]},
Composition[i[#,l+3d+2+r[d+2],-1]&,t@i[t@#,l+2d+1+r[d+1],1]&,i[#,l+d+r[d+1,1,-1],1]&,
t@i[t@#,l+r[d,1,-1],-1] &][#,15]]&,{{1}},(n-1)/2]

Exemplo

 s{15]

{{197, 193, 191}, {139, 137}, {199, 101, 97, 181}, {61, 59, 131}, {103, 37, 31, 89, 179}, {149, 67, 17, 13}, {5, 3, 29}, {151, 19, 2, 11, 53, 127}, {107, 41, 7}, {71, 23}, {109, 43, 47, 83, 173}, {73, 79}, {113}, {157, 163, 167}, {211, 223}}

Para melhorar a exibição:

 %// MatrixForm

matriz


4

Mathematica, 118 bytes

f=Permute[Range[#*#],Accumulate@Take[Join[{#*#+1}/2,Flatten@Table[(-1)^j i,{j,#},{i,{-1,#}},{j}]],#*#]]~Select~PrimeQ&

Isso gera a espiral Ulam na forma linear, observando que a posição de cada número subsequente pode ser acumulada como

{(n*n + 1)/2, +1, -n, -1, -1, +n, +n, +1, +1, +1, -n, -n, -n, ...}

ou seja, comece do centro e mova 1 para a direita, 1 para cima, 2 para a esquerda, 2 para baixo, 3 para a direita, 3 para cima, ...

Resultado:

In[515]:= f[5]
Out[515]= {17,13,5,3,19,2,11,7,23}

1

Javascript, 516 363 304 276 243 240 bytes

Minha solução não cria uma matriz densa com a espiral, mas retorna o índice que corresponde ao número especificado na matriz de Ulam da ordem dada. Então, ele percorre os números entre 2 e M * M e cria uma matriz de números primos com o idx fornecido pelo fn ulamIdx

M=15;
$=Math;
_=$.sqrt;
/**
 * Return M*i+j (i.e. lineal or vector idx for the matrix) of the Ulam Matrix for the given integer
 * 
 * Each Segment (there are 4 in each round) contains a line of consecutive integers that wraps the 
 * inner Spiral round. In the foCowing example Segments are: {2,3}, {4,5},
 * {6,7}, {8,9}, {a,b,c,d}, {e,f,g,h}, {i,j,k,l}, {m,n,o,p}  
 *            
 *    h g f e d
 *    i 5 4 3 c
 *    j 6 1 2 b
 *    k 7 8 9 a 
 *    l m n o p
 * 
 * @param n integer The integer which position in the Matrix we want.
 * @param M integer Matrix Order. 
 */
/*
 * m: modulus representing step in segment in current spirtal round
 * v: Step in current spiral round, i.e. n - (inner spirals greatest num.)
 * s: the current Segment one of [1, 2, 3, 4] that represents the current spiral round 
 * L: Segment Length (Current spiral round Order - 1)
 * B: inner Spiral Order, for trib¿vial case 1 it's -1 special case handled differently.
 * C: relative line (row or column) corresponding to n in current spiral Round 
 * R: relative line (column or row) corresponding to n in current spiral Round
 * N: Curren (the one that contains n) Spiral (matrix) round Order
 * D: Difference between M and the current Spiral round order.
 */

/**
 * Runs the loop for every integer between 2 and M*M
 * Does not check sanity for M, that should be odd.
 */
r=[];
for (x = 2; x < M * M; x++) {
    p=1;
    // Is Prime?
    for (k = 2; p&&k <= _(x); k++)
        if (x % k==0) p=0;
    if (p) {
        B = $.floor(_(x - 1));
        B=B&1?B:B-1;
        N = B + 2;
        D = (M - N) / 2;
            v = x - B * B;
            L = B + 1;
            s = $.ceil(v / L);
            m = v % L || L;
            C = D + (s < 3 ? N - m : 1 + m);
            R = s&2 ? D + 1 : D + N;
            w= s&1 ? M * C + R : M * R + C;
        // /*uncomment to debug*/ console.log("X:" + x + ": " + ((s&1) ? [C, R].join() : [R, C].join()));
        r[w] = x;
    }
}
alert(r);

Minified se parece com isso:

for(M=15,$=Math,_=$.sqrt,r=[],x=2;x<M*M;x++){for(p=1,k=2;p&&k<=_(x);k++)x%k==0&&(p=0);p&&(B=$.floor(_(x-1)),B=1&B?B:B-1,N=B+2,D=(M-N)/2,v=x-B*B,L=B+1,s=$.ceil(v/L),m=v%L||L,C=D+(s<3?N-m:1+m),R=2&s?D+1:D+N,w=1&s?M*C+R:M*R+C,r[w]=x)}alert(r);

Para a entrada 15, a saída é:

,,,,,,,,,,,,,,,, 197 ,,,, 193,, 191 ,,,,,,,,,,,,,,, 139, 137 , 199,, 101 ,,,, 97 ,,,,,,,, 181 ,,,,,,, 61, 59 ,,,, 131 ,, 103, 103, 37 ,,,,,, 31, 89, 179, 149, 67, 17 ,,,, 13 ,,,,,,,,,,, 5, 3, 29, ,,, 151 , 19 ,,, 2,11,, 53,, 127 ,,, 107, 41,, 7 ,,,,,,,,,,, 71 ,,,, 23 ,,,,,,, 109, 43, 47, 83, 173, 73, 79, 79, 79, 113, 113 ,,,,,, 113 ,,,,,,, ,,,,, 157 ,,,,,, 163 ,,,, 167 ,,,, 211 ,,,,,,,,,,,, 223


Isso foi um pouco de compressão. Você pode explicar seu código original e suas alterações?
Addison Crump

Tirei alguns suportes inúteis. E percebi que uI () tinha 4 condicionais com blocos semelhantes. Cada um com 3 linhas que geraram Row e Collumn para o segmento atual (consulte o docblock principal), então substituo esses 4 blocos por 11 linhas e a linha de retorno decide se llt é linha ou coluna. S & 2 é verdadeiro para s em (3,2) (segmentos superior e esquerdo); s <3, para s em (1,2) direita e superior. S & 1, para s em (1,3), determinará se os valores em ll & llt são row & col ou col & row e M (ordem espiral) × row + col preventes sobrepostos índices (como matriz de retificação, mas com idx linear incorreto, a correção seria precisa ll-1
juanmf

No loop principal (run ()) somente se i for primo (que fn foi reduzido, pois nunca é necessário testar <2 nem% 1), ele solicita o índice de i (ll, llt) na espiral, que é retificado. Em seguida, basta imprimir a matriz de resultados.
juanmf

Existem três matrizes conceitualmente importantes. Inner, curret & M. Útil para calcular linha absoluta & col. Subtrair interior para n deixa-nos com um relativo int em corrente (aquele em que n cai) em espiral. E a diferença entre a ordem de M e a atual é compensada por linha e coluna na rodada atual para obter as absolutas.
juanmf

364 -> 240 escrevendo fn logic inline e removendo testes não utilizados.
juanmf
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.