Desenhe uma rede de nós

24

Há uma rede de até 26 nós (chamados Apara Zou aa zconforme seu desejo). Cada par de nós pode ser conectado ou desconectado. Um nó pode estar conectado a no máximo 4 outros nós. Sua tarefa é desenhar a rede em um diagrama 2D. A entrada será fornecida de forma que esta tarefa seja possível (veja mais restrições na seção de saída).


Formato

Entrada

  • Pares de letras ( Aa Z, ou aa zconforme seu desejo). Eles não são classificados em nenhuma ordem.
  • Opcional - número de pares

Saída

  • Um desenho ASCII que mostra os links reais entre os nós. Nós são fornecidos por apara zou Apara Z. Use -para links horizontais e |verticais. Os links podem ter qualquer comprimento (diferente de zero), mas devem ser linhas horizontais / verticais retas que não dobram . É possível adicionar espaços, desde que não desfigurem a imagem.

Você não pode usar built-ins que ajudam no layout do gráfico. Outros embutidos relacionados a gráficos podem ser permitidos (embora as soluções sem embutidos sejam mais apreciadas). O menor código vence.


Dados de amostra

Entrada

A B
B F
B L
F K
L K
K R
K S
R P
S J
S P
J A
T V
V N

Saída

A - B - F   T - V
|   |   |       |
|   L - K - R   N
|       |   |
J ----- S - P

Entrada

H C
G H
A B
B F
B C
F G
C D
D A

Saída

A - B ----- F
|   |       |
D - C - H - G
ghosts_in_the_code
fonte
11
Considero que minhas perguntas anteriores foram suficientemente respondidas, mas observe que o novo caso de teste está errado porque a primeira linha está H Ae essa borda não está na saída especificada. Editar: problema identificado e corrigido.
Peter Taylor
2
Talvez mude para "Primeiro código (funcionando) vence"? ;-) Sério, isso é um desafio por si próprio, mesmo sem jogar golfe ...
Marco13
@ Marco13 Isso provavelmente encerraria o desafio como fora de tópico.
Dennis
@ghosts_in_the_code Por favor, não use bandeiras para fazer perguntas aos moderadores. Se você precisar de feedback sobre alguma coisa, sempre há O Décimo Nono Nó .
Dennis
@ Dennis ok, desculpe. Eu nunca estive conversando antes, então não sei como isso funciona.
ghosts_in_the_code

Respostas:

3

CJam, 142

Você não pediu uma solução ótima, determinística ou rápida, então aqui está:

qN%Sf%::c_s_&:Aff#:E;{A{;[DmrDmr]2f*}%:C;E{Cf=~.-:*}%0m1{E{Cf=$~1$.-_:g:T\:+,1>\ff*\f.+T0="-|"=f+~}%CA.++:L2f<__&=!}?}gS25*a25*L{~2$4$=\tt}/N*

Experimente online

Isso gera coordenadas aleatórias para cada letra e testa se o layout é aceitável (bordas alinhadas e sem interseções), até que seja. Fica incrivelmente lento à medida que você adiciona mais arestas.

As duas Dletras no código especificam o máximo de coordenadas x e y; Escolhi D(= 13) porque acho que deve ser suficiente para todos os casos; sinta-se à vontade para provar que estou errado. Mas você pode alterá-los para outros valores para acelerar o programa, por exemplo, o segundo exemplo deve terminar em um minuto ou dois se você usar 3 e 4.

aditsu
fonte
Não pedi uma solução rápida, mas talvez devesse ter pedido uma determinística. Mas agora que a questão está levantada há tanto tempo, não vou mudar.
ghosts_in_the_code
@ghosts_in_the_code não deve ser muito difícil torná-lo determinístico - tente todas as combinações de coordenadas. Mas provavelmente seria mais longo e mais lento, além de consumir muita memória.
Aditsu
3

C, 813 bytes

#include<map>
#include<set>
#include<cstdlib>
typedef int I;typedef char*C;I a,t,s,h;struct p{I x,y;}j,k;std::map<I,std::set<I>>l;std::map<I,p>g;C m,M="  |-";I L(I n,C q,C Q){j=g[n],h=1;for(I o:l[n])if(g.find(o)!=g.end())if(!(a=(k=g[o]).y==j.y)&&k.x^j.x)h=0;else for(I x=j.x,y=j.y,e=k.y*s+k.x,b,d=(k.x<j.x||k.y<j.y)?-1:1;a?x+=d:y+=d,(b=y*s+x)^e;m[b]=q[a])if(m[b]^Q[a]){h=0;break;}}I N(){for(auto i:g)for(I n:l[i.first])if(g.find(n)==g.end())return n;for(auto i:l)if(g.find(a=i.first)==g.end())return a;exit(puts(m));}I f(){for(I n=N(),x,y=0,b;y<s;y+=2)for(x=0;x<s;x+=2)m[b=y*s+x]==*M?g[n]={x,y},m[b]=n,L(n,M+2,M),h&&f(),L(n,M,M+2),m[b]=*M,g.erase(n):0;}I main(I c,C*v){for(;--c;l[a].insert(s),l[s].insert(a))a=v[c][0],s=v[c][1];t=l.size(),s=t|1;memset(m=(C)calloc(s,s),*M,s*s-1);for(a=1;a<s;++a)m[a*s-1]=10;f();}

Recebe entrada como argumentos da linha de comando, por exemplo:

./network AB BF BL FK LK KR KS RP SJ SP JA TV VN

Nem um pouco competitivo com a resposta do aditsu por tamanho, mas muito mais eficiente!

Isso forçará a força bruta de todas as soluções possíveis, mas reconhecerá rapidamente as falhas à medida que elas avançam. Para os dois casos de teste, ele termina quase imediatamente e parece levar apenas alguns segundos em entradas mais estranhas. Ele também não tem limitação para os nomes de nós aceitos (embora você não possa nomear um espaço |ou -) e não tem limite para o número de nós (desde que todos os nomes se ajustem a um byte, o limite prático é de 252 nós, e vai ficar lento muito antes de atingir tantos).

Há muito espaço para acelerar isso; muita saída de curto-circuito foi perdida para o golfe, e há partes que podem ser removidas dos pontos quentes. Além disso, algumas observações de simetria podem reduzir drasticamente o posicionamento dos 2 primeiros nós, entre outras coisas.


Demolir:

#include<map>
#include<set>
#include<cstdlib>
typedef int I;
typedef char*C;
I a,t,s,h;                // Variables shared between functions
struct p{I x,y;}          // Coord datatype
j,k;                      // Temporary coord references
std::map<I,std::set<I>>l; // Bidirectional multimap of node links
std::map<I,p>g;           // Map of nodes to positions
C m,                      // Rendered grid
M="  |-";                 // Lookup table for output characters

// Line rendering function
// Sets h to 1 if all lines are drawn successfully, or 0 if there is a blocker
I L(I n,C q,C Q){
  j=g[n],h=1;
  for(I o:l[n])                  // For each connection to the current node
    if(g.find(o)!=g.end())       // If the target node has been positioned
      if(!(a=(k=g[o]).y==j.y)&&k.x^j.x)h=0; // Fail if the nodes are not aligned
      else
        for(I x=j.x,y=j.y,             // Loop from node to target
          e=k.y*s+k.x,
          b,d=(k.x<j.x||k.y<j.y)?-1:1;
          a?x+=d:y+=d,(b=y*s+x)^e;
          m[b]=q[a])                   // Render character (| or -)
          if(m[b]^Q[a]){h=0;break;}    // Abort if cell is not blank
}

// Next node selection: finds the next connected node to try,
// or the next unconnected node if the current connected set is complete.
// Displays the result and exits if the entire graph has been rendered.
I N(){
  for(auto i:g)for(I n:l[i.first])  // Search for a connected node...
    if(g.find(n)==g.end())return n; // ...and return the first available
  for(auto i:l)                     // Else search for an unconnected node...
    if(g.find(a=i.first)==g.end())
      return a;                     // ...and return the first available
  exit(puts(m));                    // Else draw the grid to screen and stop
}

// Recursive brute-force implementation
I f(){
  for(I n=N(),x,y=0,b;y<s;y+=2) // Loop through all grid positions
    for(x=0;x<s;x+=2)
      m[b=y*s+x]==*M            // If the current position is available
       ?g[n]={x,y},             // Record the location for this node
        m[b]=n,                 // Render the node
        L(n,M+2,M),             // Render lines to connected nodes
        h&&f(),                 // If line rendering succeeded, recurse
        L(n,M,M+2),             // Un-render lines
        m[b]=*M,g.erase(n)      // Un-render node
       :0;
}

// Input parsing and grid setup
I main(I c,C*v){
  // Parse all inputs into a bidirectional multi-map
  for(;--c;l[a].insert(s),l[s].insert(a))a=v[c][0],s=v[c][1];
  t=l.size(),s=t|1; // Calculate a grid size
  // Allocate memory for the grid and render newlines
  memset(m=(C)calloc(s,s),*M,s*s-1);
  for(a=1;a<s;++a)m[a*s-1]=10;
  f(); // Begin recursive solving
}
Dave
fonte
Finalmente! Faz 2 meses. Eu, pessoalmente, não sou a favor de jogar uma resposta desse tipo, só me foi exigido pelas pessoas deste site.
ghosts_in_the_code
@ghosts_in_the_code se você não quiser código de golfe, existem muitos outros critérios objetivos de vitória que você pode usar (embora, obviamente, você não possa alterar esse desafio agora que ele foi publicado). Exemplos baseados em tempo seriam: mais rápido para gerar resultados em hardware específico (por exemplo, instância EC2 específica / raspberry pi / etc.), saída mais compacta para uma bateria de testes dentro de um prazo, a maior rede suportada por uma bateria de testes dentro de um limite de tempo (por exemplo, um dia, permitindo flexibilidade no hardware específico). Tente usar a sandbox na próxima vez; as pessoas podem ajudá-lo a escolher um objetivo.
Dave