Número triângulo flip


30

Digamos que você liste os números inteiros positivos em um triângulo e gire da esquerda para a direita. Dado um número, digite o número para o qual foi enviado. Este é um mapeamento auto-inverso.

         1                      1         
       2   3                  3   2       
     4   5   6    <--->     6   5   4     
   7   8   9  10         10   9   8   7   
11  12  13  14  15     15  14  13  12  11

Este é o nono elemento de A038722 , com um índice:

1, 3, 2, 6, 5, 4, 10, 9, 8, 7, 15, 14, 13, 12, 11, ...

Essa sequência reverte pedaços contíguos dos números inteiros positivos com comprimentos crescentes:

 1, 3, 2, 6, 5, 4, 10, 9, 8, 7, 15, 14, 13, 12, 11, ...
<-><----><-------><-----------><------------------>

Casos de teste:

1 -> 1
2 -> 3
3 -> 2
4 -> 6
14 -> 12
990 -> 947
991 -> 1035
1000 -> 1026
1035 -> 991
1036 -> 1081
12345 -> 12305

Entre os melhores:

Respostas:



7

Geléia , 8 7 bytes

RṁR€UFi

Obrigado a @ErikTheOutgolfer por economizar 1 byte!

Experimente online!

Como funciona

RṁR€UFi  Main link. Argument: n

R        Range; yield [1, ..., n].
  R€     Range each; yield [[1], [1, 2], [1, 2, 3], ..., [1, ..., n]].
 ṁ       Mold the left argument like the right one, yielding
         [[1], [2, 3], [4, 5, 6], ...]. The elements of the left argument are 
         repeated cyclically to fill all n(n+1)/2 positions in the right argument.
    U    Upend; reverse each flat array, yielding [[1], [3, 2], [6, 5, 4], ...].
     F   Flatten, yielding [1, 3, 2, 6, 5, 4, ...].
      i  Index; find the first index of n in the result.

6

Alice , 27 bytes

Obrigado ao Sp3000 pela .Cideia.

/o
\i@/.2:e2,tE*Y~Z.H2*~.C+

Experimente online!

Explicação

Acho que pode haver uma maneira mais curta de calcular isso usando números triangulares, mas achei que esse é um abuso interessante de um built-in, então aqui está uma solução diferente.

A idéia básica é fazer uso dos "pack" e "desempacotar" internos de Alice. "Pack", ou Z, leva dois números inteiros mapeia-os bijetivamente para um único número inteiro. "Descompactar" ou Yinverte essa bijeção e transforma um número inteiro em dois. Normalmente, isso pode ser usado para armazenar uma lista ou árvore de números inteiros em um único inteiro (grande) e recuperar os valores individuais posteriormente. No entanto, neste caso, podemos usar as funções na ordem oposta, para permitir que a natureza da bijeção funcione para nós.

Descompactar um número inteiro em dois números inteiros consiste basicamente em três etapas:

  1. Mapa ℤ → ℕ (incluindo zero) com um simples "fold". Ou seja, mapeie números inteiros negativos para naturais ímpares e números inteiros não negativos para pares naturais.
  2. Mapa ℕ → ℕ 2 , usando a função de emparelhamento Cantor . Ou seja, os naturais são escritos ao longo das diagonais de uma grade infinita e retornamos os índices:

       ...
    3  9 ...
    2  5 8 ...
    1  2 4 7 ...
    0  0 1 3 6 ...
    
       0 1 2 3
    

    Por exemplo, 8seria mapeado para o par (1, 2).

  3. Mapeie 2 → ℤ 2 , usando o inverso da etapa 1 em cada número inteiro individualmente. Ou seja, naturais ímpares são mapeados para números inteiros negativos e até naturais são mapeados para números inteiros não negativos.

Para compactar dois números inteiros em um, simplesmente invertemos cada uma dessas etapas.

Agora, podemos ver que a estrutura da função de emparelhamento do Cantor codifica convenientemente o triângulo que precisamos (embora os valores sejam um por um). Para reverter essas diagonais, tudo o que precisamos fazer é trocar o x e y coordenadas para a rede.

Infelizmente, como as três etapas acima são combinadas em uma única Y(ou Z) interna , precisamos desfazer os mapeamentos ℤ → ℕ ou ℕ → ℤ . No entanto, ao fazer isso, podemos salvar alguns bytes usando diretamente os mapeamentos ℕ + → ℤ ou ℤ → ℕ + , para cuidar do erro de um por um na tabela. Então, aqui está o algoritmo inteiro:

  1. Mapeie + → ℤ usando (n / 2) * (-1) n-1 . Esse mapeamento é escolhido de forma a cancelar o mapeamento implícito ℤ → during durante a descompactação, exceto que ele reduz o valor em 1.
  2. Descompacte o resultado em dois números inteiros.
  3. Troque-os.
  4. Empacote os valores trocados em um único número inteiro novamente.
  5. Mapa ℤ → ℕ + usando | 2n | + (n≥0) . Novamente, esse mapeamento é escolhido de forma a cancelar o mapeamento implícito ℕ → during durante o empacotamento, exceto que ele aumenta o valor em 1.

Com isso fora do caminho, podemos olhar para o programa:

/o
\i@/...

Isso é simplesmente uma estrutura para programas aritméticos lineares com entrada e saída inteiras.

.    Duplicate the input.
2:   Halve it.
e    Push -1.
2,   Pull up the other copy of the input.
t    Decrement.
E    Raise -1 to this power.
*    Multiply. We've now computed (n/2) * (-1)^(n-1).
Y    Unpack.
~    Swap.
Z    Pack.
.H   Duplicate the result and take its absolute value.
2*   Double.
~    Swap with other copy.
.C   Compute k-choose-k. That's 1 for k ≥ 0 and 0 for k < 0.
+    Add. We've now computed |2n| + (n≥0).



4

Oitava , 71 68 bytes

3 bytes salvos graças a Conor O'Brien .

x=triu(ones(n=input('')));x(~~x)=1:nnz(x);disp(nonzeros(flip(x))(n))

Isso não funciona para entradas grandes devido a limitações de memória.

Experimente online!

Explicação

Considere entrada n = 4. O código primeiro cria a matriz

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

Em seguida, ele substitui entradas diferentes de zero, a fim de coluna-major (para baixo, em seguida, do outro lado) por 1, 2, 3...:

 1     2     4     7
 0     3     5     8
 0     0     6     9
 0     0     0    10

Em seguida, vira a matriz verticalmente:

 0     0     0    10
 0     0     6     9
 0     3     5     8
 1     2     4     7

Finalmente, ele assume o n-ésimo valor diferente de zero na ordem da coluna principal, que neste caso é 6.


1
@ rahnema1 Isso eé genial! Você definitivamente deve publicá-lo como resposta, juntamente com outras sugestões muito boas. Quanto ans =, eu nunca tenho certeza que ele é válido ou não
Luis Mendo

4

Haskell , 31 bytes

r=round
f n=r(sqrt$2*n)^2-r n+1

Experimente online!

Esta resposta apenas usa a fórmula. É a resposta menos interessante aqui, mas também é a mais golfista.

Haskell , 38 36 34 bytes

x!y|x<=y=1-x|v<-y+1=v+(x-y)!v
(!0)

Experimente online!

(!0) é a função sem ponto em que estamos preocupados.

Explicação

Deixe-me começar dizendo que estou muito feliz com esta resposta.

A idéia básica aqui é que, se removermos o maior número triangular menor que a nossa entrada, podemos revertê-lo e adicionar o número triangular novamente. Então, definimos um operador !, pegamos !nossa entrada regular x, mas também pegamos um número extra y. ycontrola o tamanho do número triangular crescente. Se x>yqueremos recurse, diminuímos xpor ye aumentar ya um. Então calculamos (x-y)!(y+1)e adicionamos y+1a ele. Se x<=ychegamos ao nosso caso base, para reverter xa posição na linha do triângulo, retornamos 1-x.

Haskell , 54 bytes

f x|u<-div(x^2-x)2=[u+x,u+x-1..u+1]
(!!)$0:(>>=)[1..]f

Experimente online!

(!!)$0:(>>=)[1..]f é uma função sem ponto

Explicação

A primeira coisa que nos preocupa é f, fé uma função que pega xe retorna a xlinha th do triângulo em sentido inverso. Isso é feito calculando primeiro o x-1número triangular nd e atribuindo-o a u. u<-div(x^2-x)2. Em seguida, retornamos a lista [u+x,u+x-1..u+1]. u+xé o xth número triangular e o primeiro número na linha, u+x-1é um a menos que isso e o segundo número na linha u+1é um a mais que o último número triangular e, portanto, o último número na linha.

Uma vez que temos f, formamos uma lista (>>=)[1..]f, que é um achatamento do triângulo. Adicionamos zero à frente 0:para que nossas respostas não sejam compensadas por uma e fornecemos à nossa função de indexação (!!).

Haskell , 56 bytes

f 0=[0]
f x|u<-f(x-1)!!0=[u+x,u+x-1..u+1]
(!!)$[0..]>>=f

Experimente online!

Este é 2 bytes mais longo, mas um pouco mais elegante na minha opinião.


3

C (gcc) , 48 bytes

k,j,l;f(n){for(k=j=0;k<n;)l=k,k+=++j;n=1+k-n+l;}

Experimente online!

Provavelmente abaixo do ideal, mas estou muito feliz com este. Usa o fato de que

NTF N = T N + A057944 ( N ) - N + 1

(Se eu escrevi a fórmula corretamente, isso é.)


Você não está chamando return, mas o valor a return é usado. Esse é um comportamento indefinido.
2501

@ 2501 Enquanto o programa funcionar, é permitido. E, escrever o primeiro argumento de uma função é equivalente a retornar um valor.
Conor O'Brien

E, escrever o primeiro argumento de uma função é equivalente a retornar um valor. Não existe tal coisa na linguagem C. O padrão diz explicitamente que o uso do valor retornado de uma função que não retorna é um comportamento indefinido.
2501

1
@ 2501 Parece que você está confundindo o ambiente C (gcc) para a especificação C. Sim, o idioma / especificação C o chama indefinido, mas é implementado como tal. Então, quando digo "equivalente", estou definitivamente me referindo à implementação do C pelo gcc e pela maioria dos outros compiladores. No PPCG, não escrevemos código "perfeito" - muito código vai de encontro às especificações em prol do golfe. Como eu disse, desde que funcione, é uma resposta válida.
Conor O'Brien

@ 2501 Convido você a ler alguns artigos no meta site, particularmente este .
Conor O'Brien

2

05AB1E , 30 bytes

U1V[YLO>X›iYLOX-UY<LO>X+,q}Y>V

Experimente online!


Eu estava prestes a dizer "O quê? Uma resposta 05AB1E sem Unicode?" mas então um personagem não-ASCII o arruina ...: P Boa primeira resposta, no entanto, seja bem-vindo ao Programming Puzzles e Code Golf!
Clismique

@ Qwerp-Derp Muito obrigado! Comecei a aprender esse idioma, então não estou surpreso que minha resposta tenha sido tão ruim.
Eduardo Hoefel

2

Casca , 6 bytes

!ṁ↔´CN

Experimente online!

Explicação

!ṁ↔´CN  -- implicit input N, for example: 4
   ´ N  -- duplicate the natural numbers:
           [1,2,3,…] [1,2,3,…]
    C   -- cut the second argument into sizes of the first:
           [[1],[2,3],[4,5,6],[7,8,9,10],…]
 ṁ↔     -- map reverse and flatten:
           [1,3,2,6,5,4,10,9,8,7,15,…
!       -- index into that list:
           6

2

tinylisp , 78 bytes

(d _(q((R N T)(i(l T N)(_(a R 1)N(a T R))(a 2(a T(s T(a N R
(d f(q((N)(_ 2 N 1

Define uma função fque executa o mapeamento. Experimente online!

Ungolfed

Encontramos o menor número triangular que é maior ou igual ao número de entrada, bem como em qual linha do triângulo nosso número está. Desses, podemos calcular a versão invertida do número.

  • Se o número triangular atual for menor que N, prossiga para a próxima linha do triângulo. (Tratamos a linha superior como linha 2 para simplificar a matemática.)
  • Caso contrário, a versão invertida de N é (TN) + (TR) +2.

A função principal flipsimplesmente chama a função auxiliar _flipa partir da linha superior.

(load library)

(def _flip
 (lambda (Num Row Triangular)
  (if (less? Triangular Num)
   (_flip Num (inc Row) (+ Triangular Row))
   (+ 2
    (- Triangular Num)
    (- Triangular Row))))))

(def flip
 (lambda (Num) (_flip Num 2 1)))

1

05AB1E , 9 bytes

·LD£í˜¹<è

Experimente online!

Explicação

·L          # push range [1 ... 2n]
  D         # duplicate
   £        # split the first list into pieces with size dependent on the second list
    í       # reverse each sublist
     ˜      # flatten
      ¹<è   # get the element at index <input>-1

Infelizmente, o achatamento de matrizes não lida muito bem com listas maiores.
Ao custo de 1 byte, poderíamos fazer · t2z + ïn¹-> usando a fórmula matemática floor(sqrt(2*n)+1/2)^2 - n + 1encontrada no OEIS .


1

Lote, 70 bytes

@set/ai=%2+1,j=%3+i
@if %j% lss %1 %0 %1 %i% %j%
@cmd/cset/ai*i+1-%1

Usa um loop para encontrar o índice do número triangular pelo menos tão grande quanto n.




0

APL (Dyalog), 27 bytes

Eu tenho duas soluções no mesmo bytecount.

Um trem:

⊢⊃⊃∘(,/{⌽(+/⍳⍵-1)+⍳⍵}¨∘⍳)

Experimente online!

E um dfn:

{⍵⊃⊃((⍳⍵),.{1+⍵-⍳⍺}+\⍳⍵)}

Experimente online!

Ambas as soluções primeiro criam o triângulo invertido e depois extraem o elemento no índice indicado pelo argumento ( 1baseado em).


0

J, 25 bytes

3 :'>:y-~*:>.-:<:%:>:8*y'

Como explicação, considere f(n) = n(n+1)/2. f(r), dada a linha r, retorna o número mais à esquerda da rquinta linha do triângulo espelhado. Agora considere g(n) = ceiling[f⁻¹(n)]. g(i), dado o índice i, retorna a linha na qual o índice i é encontrado. Em seguida, f(g(n))retorna o número mais à esquerda da linha na qual o índice n é encontrado. Então, h(n) = f(g(n)) - (n - f(g(n)-1)) + 1é a resposta para o problema acima.

Simplificando, entendemos h(n) = [g(n)]² - n + 1 = ceiling[(-1 + sqrt(1 + 8n))/2]² - n + 1.

Pela aparência da fórmula de @ Arnauld, parece que:

ceiling[(-1 + sqrt(1 + 8n))/2] = floor[1/2 + sqrt(2n)].


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.