Ameobas Manhattan yang sedang tumbuh

11

*** ameoba graph **** adalah jenis pohon yang semua simpulnya memiliki nilai dari 0 hingga beberapa bilangan bulat non-negatif, dan setiap simpul tertentu dengan nilai x <N terhubung ke x + 1 node berbeda dengan nilai x + 1.

Grafik Ameoba untuk N = 3: (Ditandakan A 3 )

ameoba 3

Perhatikan bahwa 2's tidak diizinkan untuk membagikan salah satu dari 3's; tepat tiga 3 harus "milik" masing-masing 2.

Tantangan

Tugas Anda adalah secara induktif "menumbuhkan" grafik ameoba ini dalam kisi 2 dimensi dengan dengan rakus meminimalkan jarak Manhattan antara node:

  • Kasing dasar: A 0 hanyalah grafik 0.
  • Langkah induktif: A N + 1 dihasilkan dengan secara iteratif menempatkan node bernilai N + 1 sedekat mungkin ke node nilai N dalam struktur A N yang ada. (Itu hanya bisa sedekat mungkin karena tempat terdekat mungkin sudah diisi.)

Untuk langkah induktif, prosedur umum yang harus Anda ikuti adalah:

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

(Prosedur berbeda dengan hasil yang tidak bisa dibedakan tidak masalah.)

Contoh pertumbuhan untuk 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".

Program

Program yang Anda tulis harus mengambil angka dari 0 hingga 8 (inklusif) dan mengeluarkan grafik ameoba yang valid, menggunakan pola pertumbuhan induktif yang dijelaskan di atas.

Apa yang terjadi di luar 8 tidak masalah.

(A 8 berisi 46234 node yang mendorongnya. Apa pun di luar A 8 akan terlalu jauh. Terima kasih kepada Martin Büttner karena memperhatikan ini.)

Input harus berasal dari stdin atau baris perintah dan output harus pergi ke stdout atau file.

Contoh (diambil langsung dari atas)

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

* Jenis grafik ini mungkin sudah memiliki nama. Saya akui saya hanya mengada-ada. ;)


sumber
Mengingat laju pertumbuhan faktorial, dapatkah pertanyaan diubah dari berhenti di A35 menjadi berhenti di file 1 Megabyte, atau yang serupa? A10 adalah amuba pertama dengan lebih dari satu juta karakter.
isaacg
@ MartinBüttner Saya telah membuat batas 8 yaitu sekitar 50k node. Masih banyak tapi mudah-mudahan bisa dikelola.

Jawaban:

6

Mathematica, 353 288 285 275 bytes

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],"
"]<>""

Tidak Disatukan:

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
    ], "
  "] <> ""

Berikut adalah contoh output untuk n = 5:

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

Input 8membutuhkan waktu sekitar 4,5 menit.

Untuk perincian cepat algoritme saya:

Saya menggunakan dua tabel pencarian, fdan g. Yang pertama hanyalah peta tipis yang berisi sel-sel yang tidak kosong. Yang terakhir adalah daftar yang berisi semua pasangan koordinat untuk setiap nilai sel (saya pikir saya bahkan tidak perlu melacak yang lama di sini). Saya mengulangi melalui koordinat guntuk memperluas setiap sel dari iterasi terakhir. Untuk melakukan itu saya mengulangi jarak Manhattan, membuat semua vektor yang mungkin untuk setiap jarak, dan memeriksa apakah sel yang dihasilkan masih kosong (dalam hal ini saya mengisinya). Ulangi sampai cukup sel baru dibuat.

Ketika saya selesai, saya menemukan koordinat minimum dan maksimum gdan saya membuat grid yang sesuai, yang diisi dengan mencari sel-sel di dalamnya f. Sisanya hanya menggabungkan semuanya menjadi satu string dengan jeda baris.

Martin Ender
sumber
5

C - 309 305 301 275 bytes

Meh, terlalu lama ... jika hanya satu yang bisa mengetik #Datau sesuatu #define, maka C akan sangat bagus. Tentu saja -Dflag compiler dimungkinkan tetapi itu tampak seperti menipu saya, untuk memiliki karakter selain yang ada di file sumber.

Instruksi berlari:

Hati-hati! Tombol pertama yang Anda tekan setelah program dimulai merupakan input. Setelah entri karakter selain '0' hingga '8', siapa yang tahu hal-hal yang tidak terdefinisi akan terjadi.

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

Versi Ungolfed (tapi sudah memikirkan golf masa depan):

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

Sunting: Saya menyadari bahwa karena saya memindahkan deklarasi di luar main (), array tidak lagi dapat dialokasikan pada stack, jadi saya bebas menggunakan memori secara boros tanpa risiko meluap.

feersum
sumber
2

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

Sedikit tidak berbulu.

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)} 
Vektor
sumber
2

APL (Dyalog) (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}¨⍳⍵}⎕

Karakteristik kinerja: ini O (n!). Di sistem saya, hingga n = 5 itu instan; n = 6 membutuhkan satu detik, n = 7 membutuhkan satu menit dan n = 8 membutuhkan satu jam.

Versi non-golf

Uji:

      {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              

Penjelasan:

  • {... }⎕: baca baris dari keyboard, evaluasilah, dan berikan hasilnya ke fungsi.
  • 0::0: jika kode lain menimbulkan kesalahan, kembalikan satu 0. Ini karena matematika gagal ketika mencoba menghitung ukuran untuk grafik dengan 0 node, yang merupakan kasus ketika output seharusnya 0. (Versi sebelumnya memiliki ⍵=0:0, (jika input 0dikembalikan 0sebaliknya buat grafik), tetapi 0::0(coba saja dan kembali 0jika gagal) lebih pendek.)
  • M←⌈4×.5*⍨3÷⍨+/!⍳⍵: dengan asumsi output adalah lingkaran kasar (ini berfungsi), jumlah faktorial dari 1ke (= area output), bagi dengan 3 (cukup dekat ke pi), ambil akar kuadrat (memberikan jari-jari output), kalikan dengan 4, dan ambil langit-langit. Ini memberi dua kali diameter lingkaran, sehingga output cocok dengan ruang yang tersisa. Simpan di ini M.
  • V←,⍳⍴Z←' '⍴⍨2/M: Membuat matriks M-by-M ruang dan menyimpannya dalam Z. Ini akan menahan output. Menyimpan daftar koordinat semua elemen di V.
  • Z[G;G←⌈M÷2]←'0': setel elemen tengah Zke 0.
  • Z⊢{... }¨⍳⍵: kembali Z, setelah menerapkan fungsi berikut ke angka 1ke :
    • ⍵∘{... }V/,Z=⍕⍵-1: untuk setiap elemen Zdengan nilai node sebelumnya:
      • ⍵∘{... }⍺/⍺: untuk simpul saat ini, N kali,
        • ⊃F[⍋+/¨|(F←V/⍨,Z=' ')-⊂⍺]: dapatkan ruang kosong terdekat dengan simpul saat ini,
        • (... ⌷Z)←⍕⍵: dan atur spasi tersebut Zke nilai node saat ini.
marinus
sumber