Caminho mais curto de auto-evitação, dada uma sequência de voltas

15

Escreva um programa ou função que, dada uma sequência não vazia de curvas à direita ou à esquerda, produza o comprimento do caminho mais curto de auto-prevenção em uma treliça 2D com essas curvas.

A entrada deve ser tomada como uma string, com cada caractere sendo Rou Lpara uma curva à direita ou à esquerda, respectivamente.

A saída deve ser um número inteiro, o comprimento do caminho mais curto com as curvas especificadas.

Este é um gode golf - o menor código vence.

Exemplo

Dada a entrada

LLLLLLLLLLRRL

O caminho mais curto é o seguinte (começando em #):

+-+-+-+-+-+-+
|           |  
+ . + +-+-+ +
|   | |   | |  
+ +-+ + #-+ +
| |   |     |  
+ +-+ +-+-+-+
|   |          
+-+-+ . . . .

E o comprimento total deste caminho é 29(contando os -s e |s, a não +s).

Casos de teste

L 2
RRRRRRRRRR 23
LRRLRLRRRRL 15
LLRRLRRRRLLL 17
LLRRRRRRLLLL 21
LLLLRLLRRLLRL 16
LRLRLRLLRLRRL 14
RLLRRRRLLRRLRL 17
RRRRLLRLLLRLRL 20
LLLLRRLRLRRRLRL 19
RRRLRRRLRRLRLRL 20
caixa de papelão
fonte
Evitar a auto-evasão mesmo nas esquinas (por exemplo, caminhar para o sul na Main em direção a Elm e virar para o leste em Elm e depois caminhar para o norte na Main em direção a Elm e virar para o oeste em Elm é um não-não)?
Msh210
2
@ msh210 sim, ele não pode visitar o mesmo ponto duas vezes, mesmo em uma esquina.
cardboard_box

Respostas:

8

Prolog, 284 bytes

e(S,[0|X]):-e(S,X).
e([A|S],[A|X]):-S=X;e(S,X).
v(X/Y,76,Y/Z):-Z is -X.
v(X/Y,82,Z/X):-Z is -Y.
v(D,0,D).  
c([],0/0-0/1,[0/0]).
c([H|T],K/L-D/E,[K/L|C]):-c(T,I/J-X/Y,C),v(X/Y,H,D/E),K is I+X,L is J+Y,\+member(K/L,C).
n(X):-X=0;n(Y),X#=Y+1.
p(S,L):-n(L),length(X,L),e([0|S],X),c(X,_,_).

Esta é uma declaração bastante direta do algoritmo e bastante ineficiente (nem todos os casos de teste foram executados em tempo razoável, embora a maioria o tenha feito). Ele funciona através da geração de todos os comprimentos possíveis para a saída de 1 para cima ( n); gerar todas as sequências possíveis de esquerda / frente / direita desse comprimento que são consistentes com a entrada (implementada em e; o novo caminho é chamado X); depois, verifique o primeiro caminho válido ( cque chama vpara lidar com os efeitos das curvas esquerda e direita nos deltas x e y). O comprimento de retorno é a primeira saída vista emL. (+2 de penalidade, se você quiser impedir que a função retorne outras saídas possíveis para o comprimento, se você voltar atrás; nunca fica claro como os retornos da função idiossincrática do Prolog devem ser contados.)

Não há muito em truques de golfe aqui, mas há alguns. nfoi implementado com um solucionador de restrições, pois permite que mais espaço em branco seja removido sem confundir o analisador; isso pode exigir que o GNU Prolog seja usado, não tenho certeza disso. (Eu não poderia fazer o mesmo, cpois ele precisa lidar com números negativos.) A implementação de eé consideravelmente menos eficiente do que precisa, através da correspondência de uma lista de várias maneiras; o mais eficiente e([],[]).seria seis bytes a mais (permitiria S=X;remover a linha 2, mas isso é apenas um ganho de quatro em comparação com uma perda de dez). Para permitir que eu combine coordenadas e direções como um todo, ou apenas uma parte, eu as represento como X/Y(ou seja, um AST não avaliado, que pode ser comparado), permitindo que eu use a notação infix.

Prolog, 256 bytes, muito ineficiente para testar facilmente

Obviamente, como esse é o Prolog, muitas das funções são reversíveis, por exemplo, cpodem ser usadas para gerar todos os caminhos da origem para um par de coordenadas específico. Além disso, cgera naturalmente do menor para o maior. Isso significa que, em vez de solicitar um comprimento mínimo explicitamente, podemos cgerar todos os caminhos que vão a qualquer lugar e procurar o primeiro que seja consistente com a entrada:

e(S,[0|X]):-e(S,X).
e([A|S],[A|X]):-S=X;e(S,X).
v(X/Y,76,Y/Z):-Z is -X.
v(X/Y,82,Z/X):-Z is -Y.
v(D,0,D).
c([],0/0-0/1,[0/0]).
c([H|T],K/L-D/E,[K/L|C]):-c(T,I/J-X/Y,C),v(X/Y,H,D/E),K is I+X,L is J+Y,\+member(K/L,C).
p(S,L):-c(X,_,_),length(X,L),e([0|S],X).

Isso tem desempenho exponencial (O (3 n ), onde n é a saída). No entanto, consegui verificá-lo em alguns dos testes menores (demora cerca de 7 segundos para produzir 14 e 20 para produzir 15 no meu computador).


fonte
Não consegui fazer isso funcionar no TIO , mas posso estar fazendo algo bobo.
Peter Kagey em 25/04
@ PeterKagey Não sei muito sobre prólogo, mas acho que isso funciona. Para entrada "LRRLRLRRRRL"
H.PWiz
4

Pitão , 36 bytes

ff{I.u+NYY0f>r8YlQ.C+1*M._m^.j)hCdQT

Experimente online!

Isso é bem lento, mas funciona e é rápido o suficiente para entradas curtas.

O programa funciona representando direções como unidades complexas (1, -1, i, -i) e aponta como números complexos. Primeiro, converto a lista de voltas em uma lista de direções, depois giro toda a lista de n etapas, filtre as que tiverem pelo menos uma etapa entre cada volta e converto as direções em uma lista de pontos visitados e verifique se essa lista está correta. único. Eu incremento n em um loop até conseguir.

Mapeie para números complexos:

m^.j)hCdQ
m       Q    Map over the input
      Cd     Convert to ASCII codepoint
     h       Increment
 ^.j)        Raise i to that power.

Como Lpossui o ponto de código ASCII 76 e o Rponto de código ASCII 82, isso mapeia Lpara ie Rpara -i.

Mapa para direções absolutas:

+1*M._ ...
    ._      Form all prefixes
  *M        Map each to its product
+1          Add the first direction, before any turns

Forme listas de n etapas com pelo menos 1 etapa entre cada turno

f>r8YlQ.C ... T
       .C     T    Form all list of T steps
f                  Filter for lists where
  r8Y              Run length encoding of list
 >   lQ            With the first len(input) removed
                   is nonempty

Deve haver mais um movimento do que há curvas na entrada. Cada movimento está em uma direção diferente, portanto, a codificação do comprimento da execução deve ser maior que a entrada.

Mapa para os pontos visitados:

.u+NYY0  ...
.u   Y0   Reduce the following function over
          the list of steps, starting at 0.
          Return all intermediates.
  +NY     Add the new step to the current position.

Filtrar sem interseção automática:

f{I ...
f     Filter on
  I   Invariant under
 {    Deduplication

Encontrar o primeiro Tonde isso for bem-sucedido: f.

isaacg
fonte