Desenhar um caminho de permutação

20

Imagine os diagramas a seguir como conjuntos de tubos verticais cruzados.

1 2    1 2    1 2 3 4
\ /    \ /    \ / \ /
 X      |      |   |
/ \    / \    / \ / \
2 1    1 2   |   X   |
              \ / \ /
               X   X
              / \ / \
              3 1 4 2

No diagrama mais à esquerda, o 1e 2deslizar para baixo as respectivas barras, atravessar no X, e sair em lados opostos do local onde iniciada.

É a mesma idéia no diagrama do meio, mas |significa que os caminhos não se cruzam, então nada muda.

O diagrama mais à direita mostra um roteamento de tubo mais complexo que permite a 1 2 3 4entrada 3 1 4 2.

Objetivo

Seu objetivo neste desafio do código de golfe é desenhar esses "diagramas de roteamento de tubos", com uma permutação como 3 1 4 2. O programa mais curto em bytes vencerá.

Detalhes

  1. A entrada vem de stdin como qualquer permutação dos números de 1 a n separados por espaços, onde n é um número inteiro positivo. Você pode assumir que todas as informações estão bem formadas.
  2. A saída do diagrama de roteamento vai para stdout.

    • "Soltar" os números de 1 a n em ordem na parte superior do diagrama deve resultar na permutação de entrada saindo na parte inferior. (Superior e inferior são sempre camadas de barras.)
    • O diagrama não precisa ser otimamente pequeno. Pode ser quantos níveis forem necessários, desde que esteja correto.
    • O diagrama deve conter apenas os caracteres \/ X|e as novas linhas (sem números).
    • |sempre deve ser usado nas interseções mais externas, pois o uso Xnão faria sentido.
    • Alguns espaços à esquerda ou à direita são bons, desde que o diagrama esteja alinhado corretamente.

Exemplos

Uma entrada de 3 1 4 2pode produzir (o mesmo que acima)

 \ / \ /
  |   | 
 / \ / \
|   X   |
 \ / \ /
  X   X 
 / \ / \

Uma entrada de 1pode produzir

 \
  |
 /
|
 \
  |
 /

Uma entrada de 3 2 1pode produzir

 \ / \
  X   |
 / \ /
|   X
 \ / \
  X   |
 / \ /

Uma entrada de 2 1 3 4 6 5pode produzir

\ / \ / \ /
 X   |   X
/ \ / \ / \
Passatempos de Calvin
fonte
4
Ótima pergunta! Não acredito que faz apenas duas semanas que você se juntou - você parece estar em todo lugar.
Xnor
@xnor: D Muito obrigado. Mas, na verdade, tenho passado muito tempo aqui ...
Calvin's Hobbies
Um pode Xconectar - se diretamente a um |modo como o /faz? Para outro X?
Xnor
1
@xnor Não. Deve estar sempre na row of slashes, row of X's and |'s, row of slashes, row of X's and |'s, ... formato.
Hobbies de Calvin
Pode nser maior que 10?
Οurous

Respostas:

4

Python 2, 218 219 220 222 224 227 243 247 252 259 261 264

l=map(int,raw_input().split())
f=n=len(l)
o=s=n*' \ /'
while f+n%2:
 f-=1;i=f+n&1;a=s[2*i:][:2*n]+'\n|   '[::2-i]
 while~i>-n:a+='|X'[l[i+1]<l[i]]+'   ';l[i:i+2]=sorted(l[i:i+2]);i+=2
 o=a+f%2*'|'+'\n'+o
print o[:-2*n]

Adotei uma abordagem um pouco diferente: acho os swaps necessários para classificar a entrada e inverto verticalmente para obter os swaps necessários para transformar a lista classificada na entrada. Como um bônus adicional dessa abordagem, ele pode usar uma lista arbitrária de números e fornecer o caminho de permutação para transformar o tipo de entrada na entrada.

Exemplo:

$ python sort_path.py <<< '3 1 4 5 9 2 6 8 7'
 \ / \ / \ / \ / \
  |   |   |   |   |
 / \ / \ / \ / \ /
|   |   |   |   |   
 \ / \ / \ / \ / \
  |   |   |   |   |
 / \ / \ / \ / \ /
|   |   |   |   |   
 \ / \ / \ / \ / \
  |   |   |   |   |
 / \ / \ / \ / \ /
|   X   |   |   X   
 \ / \ / \ / \ / \
  |   X   |   X   |
 / \ / \ / \ / \ /
|   |   X   X   |   
 \ / \ / \ / \ / \
  X   |   X   |   |
 / \ / \ / \ / \ /
|   |   |   |   X   
 \ / \ / \ / \ / \

Melhorias:

264 -> 261: Loop externo comutado de para para enquanto.

261 -> 259: Usado em f%2vez de (c^m), porque em python os operadores aritméticos têm maior prioridade do que os operadores bit a bit.

259 -> 252: loop interno comutado de para para enquanto. Combinado ie cvariáveis.

252 -> 247: Compilação alterada e reversa para compilar apenas na ordem inversa.

247 -> 243: Adicionadas novas linhas manualmente, em vez de usar junção.

243 -> 227: Adotou o método do grc de geração de barras (obrigado grc!) E adicionou s.

227 -> 224: Movida a geração da linha de barra para o loop while interno para remover ae %4salvar um caractere usando o fatiamento estendido.

224 -> 222: Removido m.

222 -> 220: f%2+n%2->f+n&1

220 -> 219: | 1<n-1|-> |~i>-n|(espaço inicial removido)

219 -> 218: initializations combinados de oe se mudou-se a fatia até o fim.

isaacg
fonte
9

Python, 290

def g(o,u=1):
 s=['|']*o
 for i in range(o,n-1,2):v=r[i+1]in a[:a.index(r[i])]*u;s+=['|X'[v]];r[i:i+2]=r[i:i+2][::1-2*v]
 print'  '*(1-o)+'   '.join(s+['|']*(o^n%2))*u+'\n'*u+(' / \\'*n)[2*o:][:n*2]
a=map(int,raw_input().split())
n=len(a)
r=range(1,n+1)
o=1
g(1,0)
g(0)
while r!=a:g(o);o^=1

Eu fui para uma abordagem bastante básica, mas acabou um pouco mais do que eu esperava. Ele considera a lista em pares e decide se deve ou não trocar cada par. Isso é repetido para todas as linhas que cruzam até a lista corresponder à entrada.

Exemplo:

$ python path.py
5 3 8 1 4 9 2 7 6
 \ / \ / \ / \ / \
  |   |   |   X   |
 / \ / \ / \ / \ /
|   X   X   X   X
 \ / \ / \ / \ / \
  X   X   X   X   |
 / \ / \ / \ / \ /
|   X   X   |   X
 \ / \ / \ / \ / \
  X   X   X   |   |
 / \ / \ / \ / \ /
|   |   |   X   |
 \ / \ / \ / \ / \
grc
fonte
2

JavaScript HTML, 553 419

Obrigado a @izlin e @TomHart por apontar meus erros.

p=prompt();b=p.split(" "),l=b.length,d=l%2,o="",s=["","","\\/"],n="\n",a=[];for(i=0;i<l;i++){a[b[i]-1]=i+1;s[1]+=" "+s[2][i%2];s[0]+=" "+s[2][(i+1)%2];o+=" "+(i+1)}s[1]+=n,s[0]+=n;o+=n+s[1];f=1,g=2;do{var c="";for(var i=(f=f?0:1);i<l-1;i+=2)if(a[i]>a[i+1]){c+="  x ";g=2;t=a[i];a[i]=a[i+1];a[i+1]=t;}else c+="  | ";if(g==2){o+=(d?(f?"| "+c:c+"  |"):(f?"| "+c+"  |":c))+n;o+=(s[f]);}}while(--g);o+=" "+p;alert(o);

Teste aqui: http://goo.gl/NRsXEj
insira a descrição da imagem aqui insira a descrição da imagem aqui

JeffSB
fonte
Você cometeu um pequeno erro: a primeira linha deve ser os números classificados e a última linha deve ser sua entrada, como nos exemplos acima.
Izlin
Você está certo. Obrigado. Olhei para a saída do @ grc e pensei que os números eram a posição inicial. Opa
23414 JeffSB
Eu posso estar vendo isso errado, mas nas duas fotos que você postou, a última linha não é redundante porque nada muda?
TMH
Sim você está certo. Eu sabia que isso era um consenso de como eu fiz isso. Mas provavelmente não precisa ser assim. Eu vou pensar sobre isso. Obrigado pelo comentário.
23414 JeffSB
@izlin - Obrigado por perceber isso. Corrigi esse erro.
23414 JeffSB
1

Javascript - 395

378 se eu não imprimir os números na minha saída, mas parecerá muito melhor e melhorará a legibilidade.
Teste aqui . (com versão ungolfed) versão

golfed:

a=prompt(),n=a.split(" "),l=n.length,k=[],s="",i=1;for(j=0;j<l;j++){k[n[j]-1]=j+1;s+=" "+(j+1)}s+="\n";while(i++){for(j=0;j<l;j++)s+=i%2?j%2?" \\":" /":j%2?" /":" \\";for(z=0,y=0;z<l-1;z++)if(k[z]>k[z+1])y=1;if(y==0&&i!=2)break;s+="\n";for(m=i%2;m<l;m+=2){s+=i%2&&m==1?"|":"";if(k[m]>k[m+1]){[k[m],k[m+1]]=[k[m+1],k[m]];s+=i%2?"   X":"  X "}else{s+=i%2?"   |":"  | "}}s+="\n"}s+="\n "+a;alert(s)

Explicação

Primeiro subestudo a entrada, com o número do índice e altero a primeira linha com os resultados. Por exemplo

3 1 4 2
v v v v substitude with
1 2 3 4

so the first line will become:
1 2 3 4
v v v v
2 4 1 3

sorting 1,2,3,4 to 3,1,4,2 is equivalent to 2,4,1,3 to 1,2,3,4

Com essa substituição, posso usar um algoritmo de classificação por bolhas para classificar 2,4,1,3 a 1,2,3,4 e o gráfico será o mais curto possível que estamos procurando.
Se você tiver alguma idéia de como eu posso diminuir o código, basta comentar :)

Exemplo

input: 3 4 2 1 7 5 6
output:
 1 2 3 4 5 6 7
 \ / \ / \ / \
  X   |   |   | 
 / \ / \ / \ /
|   X   |   X
 \ / \ / \ / \
  X   X   X   | 
 / \ / \ / \ /
|   X   |   |
 \ / \ / \ / \
 3 4 2 1 7 5 6

Izlin
fonte
(1) Vejo que você usa a tag BR em três locais e, portanto, pode economizar um pouco colocando isso em uma variável. Além disso, você provavelmente poderia usar \ n desde a saída para um PRE.
23414 JeffSB
(2) Eu tenho tentado diferentes maneiras de lidar com o JavaScript no golfe e também tendo entrada e saída convenientes. Acho que gosto do meu método mais recente inspirado no seu prompt e alerta ... Eu uso prompt e alerta no código para que ele possa ser colado em um console e funcione para qualquer pessoa. Mas também fiz uma página da Web com um TEXTAREA e PRE para mostrar que funcionava. A página da Web substitui o prompt e o alerta para usar o TEXTAREA e o PRE - portanto, é o mesmo código e há menos confusão - talvez?
23414 JeffSB
@JeffSB Eu usei a <br>tag e a textarea apenas no jsfiddle, porque parece muito melhor. O alerta não possui fonte monoespaçada, portanto a saída parece ruim. Na minha versão golfed eu uso alerta e \ n. Sua página da web é pública?
Izlin
1

Cobra - 334 344 356 360

class P
    def main
        a,o,n=CobraCore.commandLineArgs[1:],['/','\\'],0
        c,l=a.count,a.sorted
        while (n+=1)%2or l<>a
            p,d='',(~n%4+4)//3
            for i in n%2*(c+1-c%2),p,o=p+o[1]+' ',[o.pop]+o
            for i in 1+d:c-n%2*c:2
                z=if(l[:i]<>a[:i],1,0)
                l.swap(i-z,i)
                p+=' ['|X'[z]]  '
            print[['','| '][d]+[p,p+'|'][d^c%2],p][n%2][:c*2]

Ele funciona movendo cada elemento para o local a partir da esquerda. Devido a isso, ele geralmente gera um mapa de caminho ridiculamente grande (embora ainda correto).

Exemplos:

3 1 4 2

\ / \ / 
 X   X  
/ \ / \ 
|  X  |
\ / \ / 
 X   X  
/ \ / \ 
|  X  |
\ / \ / 
 X   X  
/ \ / \ 
|  X  |
\ / \ / 
Furioso
fonte