Нарисуйте сеть узлов

24

В сети может быть до 26 узлов (названных Aпо Zили aпо zвашему желанию). Каждая пара узлов может быть подключена или отключена. Узел может быть подключен максимум к 4 другим узлам. Ваша задача - нарисовать сеть на двухмерной диаграмме. Ввод будет дан так, чтобы эта задача была возможна (см. Больше ограничений в разделе вывода).


Формат

вход

  • Пары букв ( Aдо Zили aдо zпо вашему желанию). Они не отсортированы ни в каком порядке.
  • Необязательно - количество пар

Выход

  • Рисунок ASCII, который показывает фактические связи между узлами. Узлы даются aв zили Aна Z. Используйте -для горизонтальных ссылок и |для вертикальных ссылок. Ссылки могут иметь любую (ненулевую) длину, но они должны быть прямыми горизонтальными / вертикальными линиями, которые не изгибаются . Пробелы могут быть добавлены при условии, что они не искажают изображение.

Вы не можете использовать встроенные модули, которые помогают в макете графика. Могут быть разрешены другие встроенные в графы встроенные модули (хотя решения без встроенных модулей будут более полезны). Самый короткий код выигрывает.


Образец данных

вход

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

Выход

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

вход

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

Выход

A - B ----- F
|   |       |
D - C - H - G
ghosts_in_the_code
источник
1
Я считаю, что на мои предыдущие вопросы были даны достаточные ответы, но учтите, что новый тестовый пример неверен, потому что первая строка - H Aэто ребро, а не в данном выводе. Изменить: проблема выявлена ​​и исправлена.
Питер Тейлор
2
Может быть, изменить его на «Первый (рабочий) код выигрывает»? ;-) Серьезно, это сложно
само
@ Marco13 Скорее всего, вызов будет закрыт как не по теме.
Денис
@ghosts_in_the_code Пожалуйста, не используйте флаги, чтобы задавать вопросы модераторам. Если вам нужна обратная связь, всегда есть девятнадцатый байт .
Денис
@ Денис, извини. Я никогда не был в чате раньше, поэтому я не знаю, как это работает.
ghosts_in_the_code

Ответы:

3

CJam, 142

Вы не спрашивали об оптимальном, детерминированном или быстром решении, поэтому здесь вы идете:

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*

Попробуйте онлайн

Это генерирует случайные координаты для каждой буквы и проверяет, является ли расположение приемлемым (краевые буквы выстраиваются в линию и нет пересечений), пока оно не будет. Это становится невероятно медленным, когда вы добавляете больше граней.

Две Dбуквы в коде указывают максимальные координаты x и y; Я выбрал D(= 13), потому что я думаю, что этого должно быть достаточно для всех случаев, не стесняйтесь доказать, что я неправ. Но вы можете изменить их на другие значения, чтобы ускорить программу, например, 2-й пример должен завершиться в течение минуты или двух, если вы вместо этого используете 3 и 4.

aditsu
источник
Я не просил о быстром решении, но, возможно, мне следовало спросить о детерминированном. Но теперь, когда вопрос так долго поднимался, я не буду его менять.
ghosts_in_the_code
@ ghosts_in_the_code не должно быть слишком сложно сделать его детерминированным - попробуйте все комбинации координат. Но это, вероятно, будет дольше и намного медленнее, а также потребляет много памяти.
aditsu
3

C, 813 байтов

#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();}

Принимает ввод в качестве аргументов командной строки, например:

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

Ни в коем случае не конкурент с ответом aditsu по размеру, но гораздо эффективнее!

Это перебор всех возможных решений, но быстро распознает неудачу. Для двух тестовых случаев он заканчивается почти сразу, и кажется, что на более неудобных входах это займет всего несколько секунд. Он также не имеет ограничений на допустимые имена узлов (хотя вы не можете назвать один пробел |или -) и не имеет ограничений на количество узлов (при условии, что все имена помещаются в байт, поэтому практический предел составляет 252 узла, и он станет медленным задолго до того, как достигнет такого количества

Есть много возможностей для ускорения этого; много выхода из короткого замыкания было потеряно для игры в гольф, и есть части, которые могут быть удалены из горячих петель. Кроме того, некоторые наблюдения симметрии могут значительно уменьшить расположение первых двух узлов, между прочим.


Сломать:

#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
}
Дейв
источник
В заключение! Прошло 2 месяца. Лично я не одобряю такой ответ в гольфе, от меня только требовали люди с этого сайта.
ghosts_in_the_code
@ghosts_in_the_code, если вы не хотите писать код гольф, есть множество других объективных критериев выигрыша, которые вы можете использовать (хотя, очевидно, вы не можете изменить это испытание, если оно было опубликовано). Основанные на времени примеры будут следующими: быстрее всего генерировать результаты на конкретном оборудовании (например, конкретном экземпляре EC2 / Raspberry Pi / и т. Д.), Наиболее компактный вывод для батареи тестов в течение определенного времени, самая большая сеть, поддерживаемая батареей тестов в пределах ограничение по времени (например, день, позволяющий гибкость на конкретном оборудовании). Попробуйте использовать песочницу в следующий раз; люди могут помочь вам выбрать цель.
Дейв