Observe, o desafio copiado da pergunta feita em math.stackexchange .
Recentemente, adquiri bastante habilidade em soprar bolhas. No começo, eu soprava bolhas assim:
Mas então as coisas começaram a ficar estranhas:
Depois de um tempo, eu estava soprando algumas bolhas bem estranhas:
Depois de soprar centenas, talvez até milhares dessas bolhas, minha testa de repente se enrugou com a pergunta: Dadas n bolhas, quantas maneiras diferentes você pode organizá-las? Por exemplo, se n = 1, há apenas 1 arranjo. Se n = 2, existem 2 arranjos. Se n = 3, existem 4 arranjos. Se n = 4, existem 9 arranjos.
Aqui estão os 9 arranjos de 4 bolhas:
Depois de soprar todas essas bolhas maravilhosas, decidi compartilhar o prazer de contar seus arranjos com você. Então, aqui está sua tarefa:
Objetivo
Escreva um programa, função ou similar que conte o número de maneiras pelas quais você pode organizar n
bolhas.
Entrada
n
, o número de bolhas. n> 0
Saída
O número de maneiras pelas quais você pode organizar essas bolhas.
Critérios Vencedores
Seria muito legal se pudéssemos fazer uma bolha no seu código. Quanto menor o código, mais fácil será fazê-lo. Portanto, a pessoa que cria o código com o menor número de bytes vence o concurso.
Informação extra
fonte
0
uma entrada válida?Respostas:
Python 2,
9287 bytesEm inglês simples: para calcular
a(n)
, calculamosd*a(d)*a(n-k)
para cada divisord
de todo número inteiro positivok
menor ou igual an
, somar tudo isso e dividir porn-1
.Para torná-lo mais rápido, execute o Python 3 (substituindo
/
por//
na função acima) e memorize:Se você fizer isso, ele calcula
a(50) = 425976989835141038353
instantaneamente.fonte
lru_cache()
memorize a função?lru_cache
.True
paran<2
. Acho que simn=1
, pois no Python éTrue
avaliado como 1 em contextos numéricos, masa(0)
deve retornar 0. Você pode corrigir isso com,n<2 and n or sum...
mas pode haver uma maneira mais compacta.n
, podemos ignorar com segurança esse caso de canto, pois não afeta as solicitações recursivas de aumenton
.GNU Prolog, 98 bytes
Esta resposta é um ótimo exemplo de como o Prolog pode enfrentar até os formatos de E / S mais simples. Ele funciona no verdadeiro estilo Prolog, descrevendo o problema, em vez do algoritmo para resolvê-lo: especifica o que conta como um arranjo legal de bolhas, pede ao Prolog para gerar todos esses arranjos e depois os conta. A geração ocupa 55 caracteres (as duas primeiras linhas do programa). A contagem e a E / S levam as outras 43 (a terceira linha e a nova linha que separa as duas partes). Aposto que esse não é um problema que o OP esperava que os idiomas lutassem com a E / S! (Nota: o destaque da sintaxe do Stack Exchange torna isso mais difícil de ler, não mais fácil, então eu o desativei).
Explicação
Vamos começar com uma versão em pseudocódigo de um programa semelhante que realmente não funciona:
Deve ficar bem claro como
b
funciona: estamos representando bolhas por meio de listas classificadas (que são uma implementação simples de multisets que faz com que multisets iguais sejam comparados com iguais) e um único balão[]
conta 1, com um balão maior contando igual à contagem total de bolhas dentro de mais 1. Para uma contagem de 4, este programa (se funcionasse) geraria as seguintes listas:Este programa é inadequado como resposta por vários motivos, mas o mais premente é que o Prolog não possui um
map
predicado (e escrever isso levaria muitos bytes). Então, em vez disso, escrevemos o programa mais ou menos assim:O outro grande problema aqui é que ele entrará em um loop infinito quando executado, devido à maneira como a ordem de avaliação do Prolog funciona. No entanto, podemos resolver o loop infinito reorganizando o programa levemente:
Isso pode parecer bastante estranho - estamos adicionando as contagens antes de sabermos o que elas são - mas o GNU Prolog
#=
é capaz de lidar com esse tipo de aritmética não-causal, e porque é a primeira linha deb
, e aHeadCount
eTailCount
deve ser menor queCount
(que é conhecido), serve como um método para limitar naturalmente quantas vezes o termo recursivo pode corresponder e, portanto, faz com que o programa seja sempre encerrado.O próximo passo é jogar um pouco de golfe. Removendo o espaço em branco, usando nomes de variáveis de um caractere, usando abreviações como
:-
forif
e,
forand
, usando emsetof
vez delistof
(ele tem um nome mais curto e produz os mesmos resultados nesse caso) e usando emsort0(X,X)
vez deis_sorted(X)
(porqueis_sorted
na verdade não é uma função real, Eu inventei):Isso é bastante curto, mas é possível fazer melhor. O principal insight é que
[H|T]
é realmente detalhado conforme as sintaxes da lista. Como os programadores do Lisp saberão, uma lista é basicamente feita apenas de células contras, que são basicamente apenas tuplas, e quase nenhuma parte deste programa está usando os recursos da lista. O Prolog possui várias sintaxes de tupla muito curtas (a minha favorita éA-B
a segunda preferidaA/B
, que estou usando aqui porque, nesse caso, produz saída de depuração mais fácil de ler); e também podemos escolher nosso próprio caractere úniconil
para o final da lista, em vez de ficarmos presos ao caractere de dois caracteres[]
(eu escolhix
, mas basicamente tudo funciona). Então, em vez de[H|T]
, podemos usarT/H
e obter saída deb
que se parece com isso (observe que a ordem de classificação nas tuplas é um pouco diferente da das listas, portanto, elas não estão na mesma ordem acima):É um pouco mais difícil de ler do que as listas aninhadas acima, mas é possível; pule mentalmente
x
s e interprete/()
como uma bolha (ou simplesmente/
como uma bolha degenerada sem conteúdo, se não houver()
depois dela), e os elementos têm uma correspondência 1 para 1 (se desordenada) com a versão da lista mostrada acima .Obviamente, essa representação da lista, apesar de muito mais curta, tem uma grande desvantagem; não está embutido no idioma; portanto, não podemos usar
sort0
para verificar se nossa lista está classificada.sort0
de qualquer maneira, é bastante detalhado, portanto, fazê-lo manualmente não é uma perda enorme (de fato, fazê-lo manualmente na[H|T]
representação da lista chega exatamente ao mesmo número de bytes). O principal insight aqui é que o programa, como escrito, verifica se a lista está classificada, se a cauda está classificada, se a cauda está classificada, e assim por diante; existem muitas verificações redundantes e podemos explorar isso. Em vez disso, apenas verificaremos se os dois primeiros elementos estão em ordem (o que garante que a lista seja classificada assim que a lista em si e todos os seus sufixos forem verificados).O primeiro elemento é facilmente acessível; isso é apenas o chefe da lista
H
. O segundo elemento é bastante mais difícil de acessar e pode não existir. Felizmente,x
é menor do que todas as tuplas que estamos considerando (por meio do operador de comparação generalizada do Prolog@>=
), para que possamos considerar o "segundo elemento" de uma lista de singletonx
e o programa funcionará bem. Quanto ao acesso real ao segundo elemento, o método tersest é adicionar um terceiro argumento (um argumento out) ab
, que retornax
no caso base eH
no caso recursivo; isso significa que podemos pegar a cabeça da cauda como uma saída da segunda chamada recursiva paraB
e, é claro, a cabeça da cauda é o segundo elemento da lista. Então,b
fica assim agora:O caso base é bastante simples (lista vazia, retorna uma contagem de 0, o "primeiro elemento" da lista vazia é
x
). O caso recursivo começa da mesma forma como antes (apenas com aT/H
notação em vez de[H|T]
, eH
como um extra para fora argumento); desconsideramos o argumento extra da chamada recursiva na cabeça, mas a armazenamos naJ
chamada recursiva na cauda. Então, tudo o que precisamos fazer é garantir queH
seja maior ou igual aJ
(ou seja, "se a lista tiver pelo menos dois elementos, o primeiro for maior ou igual ao segundo) para garantir que a lista termine.Infelizmente,
setof
isso se encaixa se tentarmos usar a definição anterior dec
juntamente com essa nova definição deb
, porque ele trata parâmetros não utilizados de maneira mais ou menos da mesma maneira que um SQLGROUP BY
, que não é exatamente o que queremos. É possível reconfigurá-lo para fazer o que queremos, mas essa reconfiguração custa caracteres. Em vez disso, usamosfindall
, que possui um comportamento padrão mais conveniente e tem apenas dois caracteres a mais, dando-nos esta definição dec
:E esse é o programa completo; gere padrões de bolhas de maneira concisa e depois gaste toda uma carga de bytes contando-os (precisamos de um tempo bastante longo
findall
para converter o gerador em uma lista, depois de um nome infelizmente verballength
para verificar o comprimento dessa lista, além do padrão para uma declaração de função).fonte
maplist/2-8
predicado , embora não tenha certeza de que isso diminua as coisas aqui.| ?- maplist(reverse,[A,B]). uncaught exception: error(existence_error(procedure,maplist/2),top_level/0)
maplist
é um predicado muito usado e fornecido nas principais distribuições do Prolog (como SWI-Prolog e SiCStus)Mathematica, 68 bytes
Aposto que isso pode ser derrotado (mesmo no Mathematica) com uma implementação a partir do zero, mas aqui está a versão interna:
ButcherTreeCount
é indexado em 0, daí o[#+1]
, e retorna uma lista de todos os valores até seu argumento, portanto, oLast@
. Mas, caso contrário, é apenas o componente interno para esta função. No entanto, requer o carregamento de um pacote, que é o que a primeira linha faz.fonte