Вирощування Манхеттенського Амеобаса


11

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

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

амеоба 3

Зауважте, що двом особам заборонено ділитися жодним із 3-х; рівно три 3 повинні "належати" кожному 2.

Виклик

Ваше завдання - індуктивно "виростити" ці графіки амеби в двовимірній сітці, жадібно мінімізуючи відстань між Манхеттеном між вузлами:

  • Базовий регістр: A 0 - це просто графік 0.
  • Індуктивний крок: A N + 1 генерується шляхом ітеративного розміщення нових вузлів з оцінкою N + 1 максимально наближеними до вузлів N значень у існуючій структурі A 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, не має значення.

8 містить 46234 вузли, які штовхають його. Все, що перевищує A 8, було б занадто далеко. Дякую Мартіну Бюттнеру, що помітив це.)

Вхід повинен надходити з 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 - перша амеба, що має понад мільйон символів.
isaacg

@ MartinBüttner Я зробив обмеження 8, яке становить близько 50k вузлів. Ще багато, але, сподіваємось, керований.

Відповіді:


6

Математика, 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],"
"]<>""

Безголівки:

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

Безгольова (але вже думає про майбутній гольф) версія:

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 (), масиви більше не можна виділяти на стек, тому я вільний використовувати пам'ять у розширеному вигляді без ризику переповнення.


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значення поточного вузла.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.