Растущий Манхэттен Амеобас

11

График *** ameoba **** - это тип дерева , все узлы которого имеют значения от 0 до некоторого неотрицательного целого числа N, и любой конкретный узел со значением x <N соединяется с x + 1 различными узлами со значениями x + 1.

Граф Амеоба для N = 3: (обозначается A 3 )

амеба 3

Обратите внимание, что 2 не имеют права делиться любым из 3; ровно три 3 должны «принадлежать» каждому 2.

Вызов

Ваша задача состоит в том, чтобы индуктивно «вырастить» эти графы амебы в двумерной сетке, жадно минимизируя расстояние Манхэттена между узлами:

  • Базовый случай: 0 просто график 0.
  • Индуктивный шаг: N + 1 , генерируется путем итеративного размещения нового N + 1 оцененных узлов как можно ближе к значениям узлов N в существующем N структуре. (Это может быть только как можно ближе, так как ближайшие места уже могут быть заполнены.)

Для индуктивного шага вы должны следовать общей процедуре:

for each existing node P with value N:
    for each new N+1 valued node Q you need to connect to P: //this loops N+1 times
        find the set of vacant spots that are minimally distant from P //by Manhattan distance
        place Q in any of these vacant spots

(Различная процедура с неразличимым выводом подойдет.)

Пример роста для A 4 :

A0 is always the same:

0

For A1 I happen to put the 1 to the right of the 0 (it has to go on one of the 4 open sides):

01

For A2 I happen to put the two 2's above and to the right of the 1:

 2
012


For A3 I find that one of the six 3's I must place cannot be directly next to a 2, so I put in one of the next closest places:

 3
323
0123
  33 <-- this 3 is distance two away from its 2

The process continues in A4. Note that I'm iterating over each 3 and placing four 4's next to it or as close as possible, then moving to the next 3 (the order of 3's does not matter):

 444
443444
4323444
4012344
 44334
  4444
   44

Always keep in mind that nodes cannot be "shared".

программа

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

То, что происходит после 8, не имеет значения.

(A 8 содержит 46234 узлов , который толкают его. Все , что за A 8 будет слишком далеко. Благодаря Мартин Büttner для заметив это.)

Входные данные должны поступать из stdin или из командной строки, а выходные данные - из stdout или файла.

Примеры (взяты непосредственно сверху)

Input: 0
Output:

0

Input: 1
Output:

01

Input: 2
Output:

 2
012

Input: 3
Output:

 3
323
0123
  33

Input: 4
Output:

 444
443444
4323444
4012344
 44334
  4444
   44

* Эти типы графиков могут уже иметь имя. Я признаю, что только что сделал их. ;)


источник
В свете факторной скорости роста можно ли изменить вопрос с остановки на A35 на остановку в файле размером 1 мегабайт или что-то подобное? A10 - первая амеба с более чем миллионом символов.
Исаак
@ MartinBüttner Я установил лимит 8, который составляет около 50 тыс. Узлов. Все еще много, но, надеюсь, управляемым.

Ответы:

6

Mathematica, 353 288 285 275 байт

n=Input[];f@_=" ";g={z={0,0}};i=f@z=0;For[r=Range,i++<n,g=Reap[(j=i;o={};For[d=0,j>0,o=Rest@o,If[o=={},o=Join@@({e={#,d-#},-e,e={d-#,-#},-e}&/@r@++d)];If[f[c=#&@@o+#]==" ",f@c=i;Sow@c;--j]])&/@g][[2,1]]];Riffle[(x=#;ToString@f@{x,#}&/@m~r~M)&/@r[m=Min@{g,0},M=Max@g],"
"]<>""

Ungolfed:

n = Input[];
f@_ = " ";
g = {z = {0, 0}};
i = f@z = 0;
For[r = Range, i++ < n,
  g = Reap[(
        j = i;
        o = {}; 
        For[d = 0, j > 0, o = Rest@o,
         If[o == {}, 

          o = Join @@ ({e = {#, d - #}, -e, e = {d - #, -#}, -e} & /@  
              r@++d)
          ];  
         If[f[c = # & @@ o + #] == " ",
          f@c = i;
          Sow@c;
          --j 
          ]   
         ]   
        ) & /@ g
     ][[2, 1]] 
  ];  
Riffle[(
     x = #;
     ToString@f@{x, #} & /@ m~r~M
     ) & /@ r[m = Min@{g, 0}, 
    M = Max@g
    ], "
  "] <> ""

Вот пример вывода для n = 5:

      5
     5555     
    555555    
   5555555    
  555555555   
 55555555555  
5555554445555 
5555544444555 
 5555443305555
 55554432144555
 55555443234555
  5555544344555
   555554445555
    5555555555
      5555555 
       55555  
       55     

Ввод 8занимает около 4,5 минут.

Для быстрой разбивки моего алгоритма:

Я использую две справочные таблицы, fи g. Первая - это просто разреженная карта, содержащая непустые ячейки. Последний представляет собой список, содержащий все пары координат для каждого значения ячейки (я думаю, мне даже не нужно отслеживать старые здесь). Я перебираю координаты, gчтобы расширить каждую ячейку с последней итерации. Для этого я перебираю манхэттенские расстояния, создавая все возможные векторы для каждого расстояния и проверяя, пуста ли получающаяся ячейка (в этом случае я ее заполняю). Повторяйте, пока не будет создано достаточно новых клеток.

Когда я закончу, я нахожу минимальную и максимальную координаты gи создаю соответствующую сетку, которая заполняется поиском ячеек f. Остальное просто объединяет все в одну строку с переносами строк.

Мартин Эндер
источник
5

C - 309 305 301 275 байтов

Мех, слишком долго ... если бы только один мог печатать #Dили что-то вместо этого #define, то C был бы действительно великолепен. Конечно, -Dфлаги компилятора возможны, но мне кажется, что это обман, чтобы иметь символы, отличные от символов в исходном файле.

Инструкция по эксплуатации:

Быть осторожен! Первая клавиша, которую вы нажимаете после запуска программы, представляет собой ввод. После ввода символа, отличного от '0' до '8', который знает, какие неопределенные вещи произойдут.

#define F(D,O)x=*r+O d;for(c=d;h*c--;x+=D)!g[x]?g[*w++=x]=l,--h:5;
L=400;g[1<<18];n;s;*r;*w;*m;h;l;d;x;main(c){n=getch()-32;r=w=g+L*L;for(l=g[*w++=80200]=16;l++<n;)for(m=w;r<m;r++)for(d=1,h=l-16;h;d++){F(L+1,-)F(L-1,-L*)F(-L+1,L*)F(~L,)}for(n=L*L;--n;)putch(n%L?g[n]+32:10);}

Ungolfed (но уже думает о будущем игре в гольф) версия:

void exit(int);

#define L 400

#define FIND(D, X0)   x = *pread X0 d; \
                for(c = d; c--; x+=D) { \
                    if(x%L == 0 || x%L == L-1 || x/L == 0 || x/L == L-1) \
                        exit(5); \
                    if(!g[x]) { \
                        g[*pwrite++ = x] = '0' + l; \
                        if(!--children) \
                            goto pnext; \
                    } \
                }

main()
{
    int n = getch() - '0';
    //char g[3] = {};
    char g[L*L] = {};
    int plist[46324];

    int *pwrite = plist, *pread = plist;
    *pwrite++ = L/2*L + L/2;
    g[*plist] = '0';
    int factorial = 1;
    int l,  c, parents, children, d, x;
    for(l = 1; l <= n; l++) {
        for(parents = factorial; parents--; pread++) {
            children = l;
            for(d = 1; ; d++) {
                FIND(L + 1, - )
                FIND(L - 1, -L* )
                FIND(-L + 1, +L* )
                FIND(-L - 1, + )
            }
            pnext:;
        }
        factorial *= l;
    }
    int i;
    for(i = L*L; i--; )
        putch(i%L ? (g[i] ? g[i] : ' ') : '\n');
}

Редактировать: я понял, что, поскольку я переместил объявления за пределы main (), массивы больше не могут быть размещены в стеке, поэтому я могу свободно использовать память без риска переполнения.

feersum
источник
2

Рубин - 296

g=[s=' ']*d=10**6
$*[g[50500]=0].to_i.times{|c|d.times{|x|g[x]==c&&(r=1;a=c;(4.times{|v|r.times{|w|g[q=x+r*(1e3*(v-1-v/2)+v%2-v/2)+w*(1e3*~0**(v/2)+~0**v)]==s&&a>~0?(g[q]=c+1;a-=1):0}};r+=1)while~0<a)}}
g=g.join.scan(/.{1000}/)
g.map{|s|s[/\d/]&&(puts s[g.map{|s|s[/\A */].size}.min..-1].rstrip)}

Слегка разгульный.

g=[s=' ']*d=10**6 # Initialize a big 1d array as a 2d grid
$*[g[50500]=0].to_i.times{|c| # For n times
    d.times{|x| # For each index in the grid
        g[x]==c&&( # If the element at x is equal to the current growth stage, c
            r=1;   # Initial manhattan radius = 1
            a=c;   # a is number of times the ameoba must replicate
            (4.times{|v| # For each of the 4 sides of the manhattan diamond
                r.times{|w| # For each node in each side
                    # Spawn the 'c+1' ameoba's from the c ameobas... 
                    # The messy formula gives the index of the space in the grid to try spawning
                    g[q=x+r*(1e3*(v-1-v/2)+v%2-v/2)+w*(1e3*~0**(v/2)+~0**v)]==s&&a>~0?(g[q]=c+1;a-=1):0 
                }
            };
            r+=1 # Increase the raidus of the manhattan diamond by one
            ) while~0<a # while not enough ameoba's have been spawned
        )
    }
}
g=g.join.scan(/.{1000}/) # Join the 1d array into a huge string and slice it into rows
# Strip away the empty spaces all around the graph and print it
g.map{|s|s[/\d/]&&(puts s[g.map{|s|s[/\A */].size}.min..-1].rstrip)} 
Векторизованное
источник
2

APL (Дьялог) (121)

{0::0⋄V←,⍳⍴Z←' '⍴⍨2/M←⌈4×.5*⍨3÷⍨+/!⍳⍵⋄Z[G;G←⌈M÷2]←'0'⋄Z⊣{⍵∘{⍵∘{+((⊃F[⍋+/¨|(F←V/⍨,Z=' ')-⊂⍺])⌷Z)←⍕⍵}¨⍺/⍺}¨V/⍨,Z=⍕⍵-1}¨⍳⍵}⎕

Характеристики производительности: это O (n!). В моей системе до n = 5 это происходит мгновенно; n = 6 занимает секунду, n = 7 занимает минуту, а n = 8 занимает час.

Версия без гольфа

Тест:

      {0::0⋄V←,⍳⍴Z←' '⍴⍨2/M←⌈4×.5*⍨3÷⍨+/!⍳⍵⋄Z[G;G←⌈M÷2]←'0'⋄Z⊣{⍵∘{⍵∘{+((⊃F[⍋+/¨|(F←V/⍨,Z=' ')-⊂⍺])⌷Z)←⍕⍵}¨⍺/⍺}¨V/⍨,Z=⍕⍵-1}¨⍳⍵}⎕
⎕:
      5





           5555             
          555555            
         55555555           
        5555445555          
       555544445555         
      55554433445555        
     5555444323445555       
    5555544321455555        
     555554430455555        
     555555444555555        
       555555555555         
        5555555555          
         55555555           
          55555             
           555              

Объяснение:

  • {...}⎕ : прочитать строку с клавиатуры, оценить ее и передать результат функции.
  • 0::0: если другой код вызывает ошибку, вернуть один 0. Это связано с тем, что математика завершается неудачно при попытке вычислить размер для графа с 0 узлами, что является случаем, когда вывод должен быть 0. (В предыдущей версии было ⍵=0:0(если входные данные 0возвращаются, в 0противном случае создайте график), но 0::0(просто попробуйте и верните0 случае неудачи) короче.)
  • M←⌈4×.5*⍨3÷⍨+/!⍳⍵: предполагая, что на выходе получился грубый круг (это работает), сложите факториалы от 1до (= область вывода), разделите на 3 (достаточно близко к пи), возьмите квадратный корень (давая радиус вывода), умножьте на 4, и возьми потолок. Это дает вдвое больший диаметр круга, поэтому выход соответствует размеру места. Сохраните это вM .
  • V←,⍳⍴Z←' '⍴⍨2/M: создайте матрицу M-by-M пространств и сохраните ее в Z. Это будет держать вывод. Сохраните список координат всех элементов в V.
  • Z[G;G←⌈M÷2]←'0': установите средний элемент Zв0 .
  • Z⊢{... }¨⍳⍵: возвращение Zпосле применения следующей функции для чисел 1в :
    • ⍵∘{... }V/,Z=⍕⍵-1: для каждого элемента вZ со значением предыдущего узла:
      • ⍵∘{... }⍺/⍺: для текущего узла, N раз,
        • ⊃F[⍋+/¨|(F←V/⍨,Z=' ')-⊂⍺]: получить свободное место ближе к текущему узлу,
        • (... ⌷Z)←⍕⍵: и установите это пространство в Zзначение текущего узла.
Мэринус
источник