Representação mais curta de um número de Subcarga

13

Texto de sabor

O baseado em pilha esolang Underload tem alguns laços interessantes para programação funcional. Um deles é o tratamento do tipo de dados numérico - como o cálculo lambda, você representa o número natural N por uma função que executa uma ação N vezes.

Para simplificar, consideraremos apenas o seguinte subconjunto de comandos Underload:

  • : - Este comando duplica o item superior da pilha.
  • * - Este comando concatena os dois principais itens da pilha em um único item.

Definimos um número N de Subcarga como uma string :e *que, quando executado, consome o item superior na pilha e produzimos N cópias desse item concatenadas juntas. Alguns exemplos:

  • Não há números de carga insuficiente 0, -1, 1/2, π.
  • A cadeia vazia é o número 1 de Carga insuficiente, porque deixa a pilha intocada.
  • :*é o número 2 de Carga insuficiente, porque duplica o item superior e concatena essas duas cópias juntas em um único item: (A):*= (A)(A)*= (AA).
  • ::**é o número 3 da subcarga: (A)::**= (A)(A):**= (A)(AA)*= (AAA).
  • :::*** é o número de Underload 4.
  • :*:*é também o número 4 da carga insuficiente: (A):*:*= (AA):*= (AA)(AA)*= (AAAA).

Em geral, você encontrará que, se Me Nsão os números M de Subcarga M e N, então :N*é o número N + 1 e MNé o número M × N.

O desafio

Sua tarefa é escrever o programa mais curto (recebendo entrada em STDIN) ou a função (recebendo entrada por argumento) que produz a representação mais curta do número de Underload para sua entrada como uma string. Ou seja, se a entrada for um número natural positivo N> 1, você deverá produzir um número N de Subcarga N cujo comprimento em caracteres seja menor ou igual ao de qualquer outro número de Underload N.

Entradas e saídas de amostra: ("Input - OUTPUT.")

  • 1 - .
  • 2 - :*.
  • 5 - ::*:**(2 × 2 + 1).
  • 7 - ::*::***(2 × 3 + 1) ou :::**:**(3 × 2 + 1).
  • 33 - ::*:*:*:*:**(2 × 2 × 2 × 2 × 2 + 1).
  • 49 - ::*:*:*:*::***(16 × 3 + 1, comprimento 14), mas não ::*::***::*::***(7 × 7, comprimento 16).

Se a entrada não for um número natural positivo, você poderá retornar um erro, produzir um comportamento indefinido ou até falhar ao finalizar. Uma explicação do método do seu envio de encontrar a resposta é apreciada.

Aplicam-se restrições de brecha padrão: nenhuma entrada extra, nenhuma solicitação da Web, valor de saída / retorno deve ser exatamente a resposta e não um fluxo aleatório infinito de :e *etc.

algoritmshark
fonte
@ Geobits Eu não disse nada sobre o tempo de execução, desde que você possa provar que ele dará a resposta correta eventualmente, você é bom.
algorithmshark
2
Esse problema está relacionado a cadeias de adição; especificamente, o comprimento da resposta correta para entrada xé 2*A117498(x)onde A117498 fornece a combinação ideal de métodos binários e de fatores para encontrar uma cadeia de adição.
Peter Taylor

Respostas:

4

GolfScript ( 61 60 55 54 53 caracteres)

~:X'']({:A{.'.+'\*A{2$+}%~}%}*{,}${1\~X=}?{44/'*:'=}%

Isso é menos complicado do que minha versão anterior e adota uma abordagem um pouco diferente, mas ainda é uma força bruta. Sabemos que essa ':'X*'*'X*+é uma solução candidata; portanto, se gerarmos todas as seqüências de caracteres bem equilibradas até esse comprimento e tomarmos a menor que avaliar a coisa certa, podemos encontrar uma.

# Evaluate input and store the target number in X
~:X
# Seed the generator with the empty string
'']
# X times...
({
    # Store the array of strings so far into A
    :A
    # Generate A' by mapping each element
    {
        # Dup: this leaves an untouched copy of the current string
        .
        # Wrap the duplicate in .+
        '.+'\*
        # For each element in A, generate that element suffixed with the current string
        A{2$+}%~
    }%
}*
# Order by length
{,}$
# Find the first element which evaluates to X
{1\~X=}?
# tr .+ :*
{44/'*:'=}%

Graças a Howard, de cuja solução eu roubei alguns ajustes de 1 caractere.

Peter Taylor
fonte
Haha, uma entrada de 3 leva mais de três segundos para ser executada no interpretador da web. Golfe no seu melhor.
algorithmshark
@algorithmshark, você pode acelerar bastante com um ponto de desduplicação. Insira .&logo após o loop interno (ou seja, entre ~}%e }*.
Peter Taylor
4

GolfScript ( 54 53 caracteres)

Essa é uma abordagem que está no espírito de Howard (construa cadeias que avaliam o valor correto e selecionam a força mais curta, em vez de bruta, através de cadeias candidatas para encontrar aquelas que avaliam o valor correto), mas é suficientemente diferente que eu acho Pertence a uma resposta separada.

~.''':*':s@,{):x,2>{:^~$x^/~$+{s\*}x^%*}%{,}$0=}/]((=

A demonstração online não está disponível porque executa uma versão com erros do intérprete.

# Let <N> denote the string which evaluates to N
# We want to enter the main loop with three values on the stack: <0> <1> <2>
# However, we'll never use <0>, so we can actually replace that with any value at all.
# Getting the input from underneath 3 items would normally use two stack manipulations.
# Trick: let's use the input value for <0>! (This gives a further bonus later).
# NB We store the value of <2> in the variable s
~.''':*':s@
# for x=1 to input_value ...
,{):x
    # for ^=2 to x-1 ...
    ,2>{:^
        # Use negative stack offsets to index the stack from the start
        # I.e. -1$ gets the first item on the stack, which is <0>
        # -2$ gets the second item on the stack, which is <1>
        # In general, val~$ gets <val>
        ~$x^/~$+
        # We have the string <^><x / ^> on the stack.
        # Increment it (x % ^) times to get a candidate <x>.
        {s\*}x^%*
    }%
    # Select a shortest string.
    {,}$0=
}/
# Group the stack into one array and select the appropriate offset,
# reusing that hacky <0> substitute for the offset.
]((=
Peter Taylor
fonte
Seria possível fazer a barba por uma substituindo 3+por )(explorando o fato de que []0=não deixa nada na pilha) se não fosse isso []2>leva a um erro.
Peter Taylor
[]2>produz []sem erro.
274 Howard
@ Howard, ah, golfscript.apphb.com deve estar executando uma versão antiga. Mas acontece que eu estava errado, porque essa substituição leva a obter a saída errada para entrada '1'.
Peter Taylor
Com o qual você pode corrigir em ((=vez de -1=.
24414 Howard Howard
E golfscript.apphb.com realmente executa uma versão antiga, o exemplo de loops aninhados não funciona.
24514 Howard Howard
4

Python 2.7 - 87 84 92

u=lambda n:n>1and min([u(i)+u(n/i)for i in range(2,n)if n%i<1]+[':'+u(n-1)+'*'],key=len)or''

Explicação:
Esta é uma solução bastante direta. Ele testa recursivamente todas as representações possíveis de n como o produto de dois números ou como :(n-1)*e, em seguida, encontra a solução de comprimento mínimo. o intervalo (2, n) é necessário para que a recursão tenha profundidade delimitada, e n <2 fornece o caso base.

Notas:
i e n / i são os dois fatores de n. O ... e ... ou ... substituto para ... se ... mais ... não funcionar porque '' é avaliado como falso. min de strings fornece uma das strings mais curtas. Python 2.7 salva 1 caractere usando / em vez de //.

Editar: moveu o caso base para a parte de trás da expressão, permitindo-me usar ... e ... ou ... e raspar alguns espaços.

Casos de teste:

u(1)
''
u(5)
'::*:**'
u(49)
'::*:*:*:*::***'
isaacg
fonte
1
" min de cadeias fornece uma das cadeias mais curtas " não é verdadeiro, a menos que você forneça o argumento opcional key=len. Ele fornece a cadeia lexicograficamente mais antiga. ( Exemplo ). Como '*' < ':'isso significa que você tem uma tendência para soluções que envolvam potências de 2, mas elas sempre são as mais curtas?
Peter Taylor
1
Resposta: na verdade, o viés é mais complicado, mas nem sempre fornece a resposta correta. O menor contra-exemplo é u(33), para os quais a classificação lexicograficamente dá o 14-char ::**::*::*:***mas a classificação por comprimento dá o 12-char::*:*:*:*:**
Peter Taylor
1
Eu nunca soube disso sobre comparações de strings em Python. Eu atualizei minha resposta.
Isaacg
3

GolfScript, 63 58 56 caracteres

~n./\{:v~[':*'1$*v,,2>{v,\%!},{.v=v,@/v=+}/]{,}$0=]}*-2=

O código recebe entrada no STDIN e imprime o resultado.

Exemplos:

> 49
:::**:*:*:*:**

> 1234
::::*:*:*:**:*:*:**::**::***

Você pode testar seus próprios casos online .

Howard
fonte
Uau, eu pensei que uma abordagem baseada em fatoração seria um pouco mais longa do que uma abordagem de força bruta.
Peter Taylor
@ PeterTaylor Eu também pensava, mas acabou que não é o caso. Além disso, a minha solução de força bruta foi um pouco mais do que o seu ;-)
Howard
Você se importaria de explicar o que cada porção faz? Só posso acompanhar até um :x(=pouco. Além disso, +1 por ser capaz de executar 49 em um período de tempo razoável.
algorithmshark
@algorithmshark Ainda estou trabalhando na solução, para que ela ainda mude muito (como aconteceu). Principalmente, a parte x,2>{x\%!},dá todos os verdadeiros divisores de x, {.v=x@/v=+}/em seguida, concatena as soluções para de x/dpara todos os divisores d. {,}$classifica-os por comprimento e 0=leva o menor deles (mais o :(x-1)*caso inicial ).
Howard
2

Brachylog 2 , 30 (talvez até 26) bytes, desafio de pós-datas no idioma

Aqui está uma função que funciona com a implementação atual do Brachylog 2 (e retorna uma lista de códigos de caracteres porque a implementação atual está tendo alguns problemas com o tratamento de strings):

∧.l∧?{ḋp~c×ᵐ{-₁↰₁:[42,58]c↻}ᵐc}

Experimente online!

A linguagem ainda é muito nova. Aqui está uma versão de 26 bytes do programa que deve funcionar de acordo com a especificação, mas usa alguns recursos não implementados e, portanto, ainda não é válido, mas talvez seja no futuro (também é ainda menos eficiente):

{ḋp~c×ᵐ{-₁↰₁:"*:"c↻}ᵐc}ᶠlᵒh

Explicação

∧.l∧?{ḋp~c×ᵐ{-₁↰₁:[42,58]c↻}ᵐc}
∧.l∧?                            Evaluation hint: try shortest outputs first
     {                        }  Define an inner function
      ḋ                          Prime factor decomposition of the input
       p                         Find a permutation
        ~c                       Find an inverse concatenation (i.e. partition)
          ×ᵐ                     Take the product of each set inside the partition
      ḋp~c×ᵐ                     Find a decomposition into factors ≥ 2
            {              }ᵐ    For each of those factors:
             -₁                  Decrement it
               ↰₁                Call the inner function recursively
                 :[42,58]c       Append "*:" (as character codes)
                          ↻      Move the last element to the start
                             c   Append the results together

A idéia básica é bastante simples: alternamos entre decompor o número em (1 ou mais) fatores (não necessariamente fatores primos, mas fatores de 1 não são permitidos) e expressar cada um deles como 1 + (uma representação obtida de um método recursivo). ligar). Isso garante a pesquisa de todas as representações possíveis de Underload do número (podemos aplicar um estágio de multiplicação "duas vezes seguidas" multiplicando juntos mais de 2 números e um estágio de incremento duas vezes seguidas, separando-os com um estágio de multiplicação que multiplica juntos apenas um número). Não precisamos de um caso base explícito, porque decompor 1 em fatores primos nos fornece uma lista vazia e, portanto, a construímos com um estágio de multiplicação que multiplica zero números juntos.

O programa é bastante ineficiente, principalmente porque a dica de ordem de avaliação que eu dei (gere respostas do menor ao maior em termos do tamanho da saída final), enquanto resolve a parte "mais curta" da pergunta, não é tão boa assim em termos de na verdade, concluir o programa rapidamente (uma dica muito mais útil seria "gerar apenas a resposta mais curta em cada estágio recursivo", mas isso exige mais bytes ...). Além disso, ḋp~c×ᵐpode gerar partições multiplicativas várias vezes cada, fazendo com que o programa faça muito trabalho redundante.


fonte
0

J - 81 char

Para a posteridade, foi o melhor que pude fazer em J.

_2{::(0&(][,0{<@;"1@({~#(#~]-:"1<.)@(],.%)2}.i.@#)(/:#&>)@,':'<@,'*',~>@{:),~)&a:

Criamos uma lista de resultados, começando com duas cadeias vazias (que são ,~e a:) representando 0 (nunca usadas) e 1 e, em seguida, iteramos um verbo sobre elas (uso furtivo de ganchos, trens e &) que acrescenta a representação mais curta do próximo número.

O verbo real que iteramos usa o comprimento da lista como um indicador de qual número estamos operando. Primeiro, fatoramos esse número em pares de fatores ( #(#~]-:"1<.)@(],.%)2}.i.@#) e recuperamos cada par puxando da matriz ( {~). Transformamos cada um desses pares (pode haver 0 deles se o número for primo) em cadeias simples ( <@;"1).

Em seguida, anexamos a essa lista a entrada do resultado anterior entre colchetes por :e *, e classificamos essa lista por length ( (/:#&>)). Finalmente, pegamos o primeiro resultado dessa lista ( 0{) e o anexamos ao final da matriz base ( [,). Quando o loop termina de iterar, temos uma lista de comprimento 2 a mais do que a entrada, começando em 0. Portanto, o que temos de retornar é a penúltima string ( _2{::).

   un =: _2{::(0&(][,0{<@;"1@({~#(#~]-:"1<.)@(],.%)2}.i.@#)(/:#&>)@,':'<@,'*',~>@{:),~)&a:
   un 49
::*:*:*:*::***
   un 1234
:*::*:*:*::*::***::*::*:****
   un 10010
:*::*:*::***::*:*:*:*:*:*:*::***
   2 * (1 + 3 * 2^2) * (1 + 3 * 2^7)
10010
   6!:2 'un 10010'   NB. time in seconds
19.5539
algoritmshark
fonte
0

Geleia , 33 bytes, desafio de pós-datas de idiomas

ÆḌḊµ⁹÷Ñ;Ñð€
’ß”:;;”*W;ÇLÞḢµ“”>1$?

Experimente online!

Uma solução simples de força bruta.

Explicação

Programa principal

’ß”:;;”*W;ÇLÞḢµ“”>1$?
              µ  >1$?  If input is greater than 1, then:
’ß                       Run recursively on the input - 1
  ”:;                    Prepend a colon
     ;”*                 Append an asterisk
        W;               Cons to:
          Ç                the result of the helper, on {the original input}
           LÞ            Sort by length
             Ḣ           Take the first (i.e. shortest) result
               “”      Otherwise, return an empty string

O programa principal usa a função auxiliar para enumerar todas as maneiras possíveis de produzir o valor por multiplicação, depois tenta produzir o valor por adição e retorna a menor possibilidade. Ele também lida com o caso base (uma entrada de 1).

Função auxiliar

ÆḌḊµ⁹÷Ñ;Ñð€
ÆḌ µ     ð€            For all proper factors of the input
  Ḋ                    except the first (i.e. 1):
    ⁹÷                   Divide it into the input;
      Ñ                  Run the main program on it;
       ;                 Append the result of:
        Ñ                  the main program run on {the factor}

A função auxiliar tenta todos os métodos possíveis de expressar a entrada como uma multiplicação de dois números e chama recursivamente o programa principal para obter suas representações mais curtas.


fonte
0

GNU Prolog, 96 bytes

v(N)-->{N#=1};{N#=A*B,A#<B,B#<N},v(A),v(B);{N#=M+1},":",v(M),"*".
s(N,S):-length(S,_),v(N,S,[]).

A primeira linha é uma gramática que implementa a avaliação de Subcarga e funciona na direção inversa (na verdade, ela não funciona na direção direta devido à A#<Brestrição; mude isso para A#<Npara um programa mais lento que funciona nos dois sentidos). A segunda linha define o predicado semelhante à função s(que é a função implementada como uma solução para este programa) que encontra a string mais curta possível que avalia o número fornecido como entrada (isso é frustrantemente detalhado para o que é uma tarefa relativamente simples, mas isso é Prolog para você ...).

O programa deve ser bastante auto-explicativo, uma vez que é mais ou menos uma tradução direta da especificação para uma gramática e, em seguida, para a sintaxe do Prolog; a definição de vdiz que Né 1 em uma sequência vazia, ou Né A× B(com Amenos que Bmenos que N) e a sequência é a concatenação de v(A)e v(B), ou Né M+ 1 e a sequência é :concatenada com v(M)concatenada com *. A segunda linha é um pouco mais sutil;length(S,_) significa "S tem algum comprimento", mas especificar isso como a primeira coisa na linha funciona como uma dica para a implementação do Prolog de que ele deve verificar primeiro os comprimentos mais curtos (o que significa que obteremos o menor comprimento possível para um valor de retorno) .


fonte