Particionando a grade em triângulos

18

Objetivo

O objetivo desse desafio é produzir uma função nque calcule o número de maneiras de particionar a n X 1grade em triângulos, onde todos os vértices dos triângulos estão em pontos da grade.

Exemplo

Por exemplo, existem 14 maneiras de particionar a grade 2 x 1, portanto, f(2) = 14através das partições a seguir, nas Partições de 2 x 1 quais as partições possuem 2, 2, 2, 2, 4 e 2 orientações distintas, respectivamente.

Pontuação

Isso é , então o código mais curto vence.

Peter Kagey
fonte
10
Alguns casos de teste adicionais seriam benéficos, para que possamos verificar se nossos envios estão corretos.
AdmBorkBork 27/11
8
Você pode especificar triângulos não degenerados .
Arnauld
1
Fiz edições na sequência O0IS A051708 para refletir essa interpretação.
Peter Kagey

Respostas:

2

05AB1E , 13 bytes

·LÉœÙεÅγo;P}O

Porto da resposta Jelly do @Bubbler .

Muito lento devido às permutações embutidas.

Experimente online ou verifique as quatro primeiras entradas .

Explicação:

·                # Double the (implicit) input
 L               # Create a list in the range [1, doubled_input]
  É              # Check for each if they're odd (1 if truthy, 0 is falsey)
                 # We now have a list of n 0s and n 1s (n being the input)
   œ             # Get all permutations of that list
    Ù            # Only leave the unique permutations
     ε     }     # Map each permutation to:
      Åγ         #  Run-length encode the current value (short for `γ€g`)
        o        #  Take 2 to the power for each
         ;       #  Halve each
          P      #  Take the product of the mapped permutation
            O    # Sum all mapped values together (and output implicitly)
Kevin Cruijssen
fonte
19

Haskell , 60 55 54 52 bytes

Depois de desenhar e programar muitos exemplos, ocorreu-me que isso é o mesmo que o problema das gralhas:

Em um tabuleiro de xadrez (n+1)×(n+1) , de quantas maneiras há uma torre para ir de (0,0) a (n,n) movendo-se apenas para a direita +(1,0) ou para cima +(0,1) ?

Basicamente, você tem a linha superior e inferior da grade 1×n . Agora você deve preencher a linha não horizontal. Cada triângulo deve ter duas linhas não horizontais. Se um dos lados faz parte do topo ou da linha de fundo corresponde à direção e ao comprimento que você seguiria no problema das gralhas. Este é o OEIS A051708 . Como ilustração dessa correspondência, considere os seguintes exemplos. Aqui, a linha superior corresponde aos movimentos para cima, enquanto a linha inferior corresponde aos movimentos para a direita.

Obrigado @PeterTaylor por -6 bytes e @PostLeftGarfHunter por -2 bytes!

b 0=1
b 1=2
b n=div((10*n-6)*b(n-1)-9*(n-2)*b(n-2))n

Experimente online!

flawr
fonte
Encontrei a sequência OEIS pesquisando com os primeiros valores. Boa explicação para o motivo. Deseja editá-lo para adicionar um comentário sobre essa interpretação combinatória alternativa? Se não, eu poderia.
Peter Taylor
BTW, você precisa ajustar a indexação, porque a resposta correta aqui é A051708(n+1). Então, eu postei o primeiro correta resposta :-P
Peter Taylor
Entendo que a torre move o mapa para triângulos, fazendo com que triângulos com as bordas superior e inferior correspondam aos movimentos para cima ou para a direita?
Neil
@PeterTaylor Porra, obrigado por apontar meu erro :)
flawr
5
@ Neil eu adicionei uma explicação gráfica.
flawr
8

Haskell , 42 bytes

0?0=1
a?b=sum[a?i+i?a|i<-[0..b-1]]
f n=n?n

Experimente online!

Uma implementação bastante direta que se repete mais de 2 variáveis.

Veja como podemos obter esta solução. Comece com o código implementando uma fórmula recursiva direta:

54 bytes

0%0=1
a%b=sum$map(a%)[0..b-1]++map(b%)[0..a-1]
f n=n%n

Experimente online!

Usando a interpretação de movimento da torre de flawr , a%bé o número de caminhos que levam a torre de (a,b)para (0,0), usando apenas os movimentos para diminuir uma coordenada. O primeiro movimento diminui aou diminui b, mantendo o outro igual, daí a fórmula recursiva.

49 bytes

a?b=sum$map(a%)[0..b-1]
0%0=1
a%b=a?b+b?a
f n=n%n

Experimente online!

Podemos evitar a repetição map(a%)[0..b-1]++map(b%)[0..a-1]observando que as duas metades são iguais ae btrocadas. A chamada auxiliar a?bconta os caminhos em que o primeiro movimento diminui ae, portanto, b?aconta aqueles em que o primeiro movimento diminui b. Em geral, são diferentes e adicionam a a%b.

O somatório em a?btambém pode ser escrito como uma compreensão da lista a?b=sum[a%i|i<-[0..b-1]].

42 bytes

0?0=1
a?b=sum[a?i+i?a|i<-[0..b-1]]
f n=n?n

Experimente online!

Finalmente, nos livramos %e escrevemos a recursão em termos de ?substituindo a%ipor a?i+i?ana chamada recursiva.

O novo caso base faz com que isso ?dê a saídas o dobro do da ?versão de 49 bytes, já que com 0?0=1nós teríamos 0%0=0?0+0?0=2. Isso permite definir f n=n?nsem a metade que precisaríamos fazer.

xnor
fonte
Sua solução de 49 bytes usa a mesma recursão da minha resposta, mas ainda não descobri a solução de 42 bytes. Uma explicação seria legal.
Peter Taylor
Acho que usei a mesma abordagem em um dos meus programas anteriores: a idéia está gerando (ou contando) todas as partições, gerando linhas não horizontais da direita para a esquerda. Você começa com a linha vertical. Em seguida, você pode recursar: Pegue um dos nós finais da linha anterior e conecte-o a um nó na linha horizontal oposta, que fica mais à esquerda de todos os nós anteriores nesta linha.
flawr
O operador a%bconta o número de partições usando os nós 0,1,...,ana linha superior e os acenos 0,1,..,bde cabeça na linha inferior. O operador a?bconta o número de maneiras pelas quais você pode adicionar uma nova linha a partir do nó superior, ase o nó inferior bjá estiver em uso. (Você pode se conectar aa todos os nós [0,1,...,b-1], mas então você tem que recurse para cada um deles.)
flawr
Flawr @, esse é o de 49 bytes, o que eu entendo. É o ?de 42 bytes que eu não conheço, e o que é particularmente curioso é que não é simétrico.
Peter Taylor
@ PeterTaylor Desculpe pela confusão, de alguma forma misturei as duas soluções. Penso que podemos facilmente transformar as duas soluções uma na outra: na primeira etapa, podemos substituir map...por uma compreensão da lista; na segunda, apenas inserimos a definição de %:a?b=sum$map(a%)[0..b-1], a%b=a?b+b?a a?b=sum[a%i|i<-[0..b-1]], a%b=a?b+b?a a?b=sum[a?i+i?a|i<-[0..b-1]]
flawr
7

CJam (24 bytes)

{2,*e!{e`0f=:(1b2\#}%1b}

Demonstração online

Isso usa a abordagem de Bubbler de somar sobre permutações de n0s e n1s.

Dissecação

{         e# Define a block
  2,*     e#   Given input n, create an array of n 0s and n 1s
  e!      e#   Generate all permutations of that array
  {       e#   Map:
    e`    e#     Run-length encode
    0f=:( e#     Extract just the lengths and decrement them
    1b    e#     Sum
    2\#   e#     Raise 2 to the power of that sum
  }%
  1b      e#  Sum the mapped values
}

Abordagem alternativa (28 bytes)

{_1aa{_2$,f{j}@@,f{j}+1b}2j}

Demonstração online

Dissecação

Todos os triângulos têm uma aresta horizontal e duas arestas que vinculam as linhas horizontais. Rotule as arestas não horizontais por uma tupla de suas duas cordas x e classifique lexicograficamente. Então a primeira aresta é (0,0), a última aresta é (n,n)e duas arestas consecutivas diferem precisamente em uma das duas posições. Isso cria uma recursão simples, que eu implementei usando o operador de recursão memorizado j:

{            e# Define a block
  _          e#   Duplicate the argument to get n n
  1aa        e#   Base case for recursion: 0 0 => 1
  {          e#   Recursive body taking args a b
    _2$,f{j} e#     Recurse on 0 b up to a-1 b
    @@,f{j}  e#     Recurse on a 0 up to a b-1
    +1b      e#     Combine and sum
  }2j        e#   Memoised recursion with 2 args
}

Nota

Esta não é a primeira vez que desejo fjreceber suporte no CJam. Aqui, a pontuação também seria reduzida para 24 bytes. Talvez eu devesse tentar escrever um patch ...

Peter Taylor
fonte
Yay, eu batê-lo por 10 segundos, eu não acho que eu já estava tão perto :)
flawr
@ flawr, eu considerei postar antes de escrever uma dissecção, mas achei que tinha tempo de eliminá-la rapidamente. Então vi "Nova resposta" e excluí minha dissecção parcialmente escrita, postei e editei.
Peter Taylor
1
Obrigado por -5 bytes btw: D
flawr
4

Geléia , 15 14 bytes

Ø.xŒ!QŒɠ€’§2*S

Experimente online!

-1 byte com base no comentário de Peter Taylor.

Usa a ilustração de flawr diretamente, em vez da fórmula resultante.

Como funciona

Ø.xŒ!QŒɠ€’§2*S    Main link (monad). Input: positive integer N.
Ø.x               Make an array containing N zeros and ones
   Œ!Q            All unique permutations
      Œɠ€         Run-length encode on each permutation
         ’§       Decrement and sum each
           2*S    Raise to power of 2 and sum

Pegue todas as rotas possíveis em uma grade quadrada. O número de maneiras de mover L unidades em uma direção como uma torre é 2**(L-1). Aplique isso a todas as rotas e some o número de maneiras de percorrer cada rota.

Bubbler
fonte
Boa abordagem. Quando eu o portava para o CJam, era mais curto diminuir os comprimentos, somar e aumentar 2 para a soma; em vez de aumentar 2 para o comprimento, reduzindo pela metade e depois multiplicando. Não sei se isso pode lhe poupar um byte.
Peter Taylor
3

Carvão , 44 31 bytes

riscado 44 ainda é regular 44

F⊕θ«≔⟦⟧ηF⊕θ⊞ηΣ∨⁺ηEυ§λκ¹⊞υη»I⊟⊟υ

Experimente online! Explicação: Funciona calculando o número de maneiras de particionar um trapézio de comprimentos laterais opostos m,nem triângulos, todos eles com desvios inteiros. Este é simplesmente um caso geral do retângulo de tamanho nna pergunta. O número de partições é dado recursivamente como a soma dos números de partições para todos os lados m,0..n-1e n,0..m-1. Isso é equivalente ao problema generalizado das torres, OEIS A035002 . O código simplesmente calcula o número de partições trabalhando 0,0até n,nusar os valores calculados anteriormente.

F⊕θ«

Faça um loop sobre as linhas 0..n.

≔⟦⟧η

Comece com uma linha vazia.

F⊕θ

Faça um loop sobre as colunas na linha 0..n.

⊞ηΣ∨⁺ηEυ§λκ¹

Leve a linha até o momento e os valores nas linhas anteriores na coluna atual e adicione a soma total à linha atual. No entanto, se não houver valores, substitua 1no lugar da soma.

⊞υη»

Adicione a linha finalizada à lista de linhas até agora.

I⊟⊟υ

Emita o valor final calculado.

Neil
fonte
2

Pari / GP , 43 bytes

De acordo com o OEIS , a função geradora dessa sequência é

12(1-x1-9x+1)

n->Vec(sqrt((1-x)/(1-9*x)+O(x^n++))+1)[n]/2

Experimente online!

alefalpha
fonte