Trồng Ameobas Manhattan


11

Biểu đồ *** ameoba **** là một loại cây có các nút có tất cả các giá trị từ 0 đến một số nguyên N không âm và bất kỳ nút cụ thể nào có giá trị x <N kết nối với x + 1 nút riêng biệt có giá trị x + 1.

Biểu đồ Ameoba cho N = 3: (Ký hiệu A 3 )

ameoba 3

Lưu ý rằng 2 không được phép chia sẻ bất kỳ trong số 3; chính xác ba 3 phải "thuộc" cho mỗi 2.

Thử thách

Nhiệm vụ của bạn là tự động "phát triển" các đồ thị ameoba này trong lưới 2 chiều bằng cách thu nhỏ khoảng cách Manhattan giữa các nút:

  • Trường hợp cơ sở: A 0 chỉ đơn giản là biểu đồ 0.
  • Bước quy nạp: Một N + 1 được tạo bằng cách lặp đi lặp lại các nút có giá trị N + 1 mới càng gần với các nút giá trị N trong cấu trúc A N hiện có . (Nó chỉ có thể càng gần càng tốt vì các điểm gần nhất có thể đã được lấp đầy.)

Đối với bước quy nạp, quy trình chung bạn phải tuân theo là:

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

(Một quy trình khác với đầu ra không thể phân biệt là tốt.)

Ví dụ tăng trưởng cho 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".

Chương trình

Chương trình bạn viết phải lấy một số từ 0 đến 8 (đã bao gồm) và đưa ra biểu đồ ameoba hợp lệ của nó, sử dụng mô hình tăng trưởng quy nạp được giải thích ở trên.

Điều gì xảy ra ngoài 8 không quan trọng.

(A 8 chứa 46234 nút đang đẩy nó. Mọi thứ ngoài A 8 sẽ quá xa. Cảm ơn Martin Büttner vì đã nhận thấy điều này.)

Đầu vào phải đến từ stdin hoặc dòng lệnh và đầu ra phải vào stdout hoặc một tệp.

Ví dụ (lấy trực tiếp từ trên)

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

* Những loại biểu đồ có thể đã có tên. Tôi thừa nhận tôi chỉ làm cho họ lên. ;)


Trong bối cảnh tốc độ tăng trưởng giai thừa, câu hỏi có thể được thay đổi từ dừng tại A35 sang dừng ở tệp 1 Megabyte, hoặc một cái gì đó tương tự? A10 là amip đầu tiên có hơn một triệu ký tự.
isaacg

@ MartinBüttner Tôi đã thực hiện giới hạn 8 là khoảng 50 nghìn nút. Vẫn còn rất nhiều nhưng hy vọng có thể quản lý được.

Câu trả lời:


6

Toán học, 353 288 285 275 byte

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

Ung dung:

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

Đây là một ví dụ đầu ra cho n = 5:

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

Đầu vào 8mất khoảng 4,5 phút.

Để phân tích nhanh thuật toán của tôi:

Tôi đang sử dụng hai bảng tra cứu fg. Cái đầu tiên chỉ là một bản đồ thưa thớt chứa các ô không trống. Cái sau là một danh sách chứa tất cả các cặp tọa độ cho mỗi giá trị ô (Tôi nghĩ rằng tôi thậm chí không cần theo dõi các cặp cũ ở đây). Tôi đang lặp qua các tọa độ gđể mở rộng mọi ô từ lần lặp cuối cùng. Để làm điều đó, tôi lặp lại khoảng cách Manhattan, tạo tất cả các vectơ có thể cho mỗi khoảng cách và kiểm tra xem ô kết quả có còn trống không (trong trường hợp đó tôi điền vào nó). Lặp lại cho đến khi đủ các ô mới được tạo.

Khi tôi hoàn thành, tôi tìm thấy tọa độ tối thiểu và tối đa gvà tôi tạo ra một lưới thích hợp, được lấp đầy bằng cách tra cứu các ô trong đó f. Phần còn lại chỉ là nối mọi thứ thành một chuỗi với các ngắt dòng.


5

C - 309 305 301 275 byte

Meh, quá lâu ... nếu chỉ có một người có thể gõ #Dhoặc một cái gì đó thay vì #define, thì C sẽ thực sự tuyệt vời. Tất nhiên các -Dcờ biên dịch là có thể nhưng điều đó có vẻ như gian lận với tôi, để có các ký tự khác với các ký tự trong tệp nguồn.

Hướng dẫn chạy:

Hãy cẩn thận! Phím đầu tiên bạn nhấn sau khi chương trình bắt đầu cấu thành đầu vào. Khi nhập một ký tự khác từ '0' đến '8', ai biết điều gì sẽ không xác định sẽ xảy ra.

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

Phiên bản Ungolfed (nhưng đã nghĩ về việc chơi golf trong tương lai):

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

Chỉnh sửa: Tôi nhận ra rằng vì tôi đã di chuyển các khai báo bên ngoài hàm main (), các mảng không còn có thể được phân bổ trên ngăn xếp, vì vậy tôi có thể tự do sử dụng bộ nhớ theo cách hoang phí mà không có nguy cơ tràn.


2

Hồng ngọc - 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)}

Hơi vô duyên.

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

Đặc điểm hiệu suất: đó là O (n!). Trên hệ thống của tôi, tối đa n = 5 là tức thời; n = 6 mất một giây, n = 7 mất một phút và n = 8 mất một giờ.

Phiên bản không chơi gôn

Kiểm tra:

      {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              

Giải trình:

  • {... }⎕: Đọc một dòng từ bàn phím, đánh giá nó và chuyển kết quả cho hàm.
  • 0::0: nếu mã khác phát sinh lỗi, hãy trả về một 0. Điều này là do toán học thất bại khi cố gắng tính kích thước cho đồ thị có 0 nút, điều này xảy ra trong trường hợp đầu ra phải như vậy 0. (Phiên bản trước có ⍵=0:0, (nếu đầu vào được 0trả lại 0bằng cách khác tạo biểu đồ), nhưng 0::0(chỉ cần thử và trả lại 0nếu thất bại) thì ngắn hơn.)
  • M←⌈4×.5*⍨3÷⍨+/!⍳⍵: giả sử đầu ra là một vòng tròn thô (công trình này), tính tổng các yếu tố từ 1đến (= diện tích đầu ra), chia cho 3 (đủ gần với pi), lấy căn bậc hai (cho bán kính đầu ra), nhân với 4, và lấy trần nhà. Điều này cho hai lần đường kính của vòng tròn, vì vậy đầu ra phù hợp với phòng để dự phòng. Lưu trữ này trong M.
  • V←,⍳⍴Z←' '⍴⍨2/M: tạo một ma trận M-by-M của khoảng trắng và lưu trữ nó vào Z. Điều này sẽ giữ đầu ra. Lưu trữ một danh sách các tọa độ của tất cả các yếu tố trong V.
  • Z[G;G←⌈M÷2]←'0': đặt phần tử ở giữa Zthành 0.
  • Z⊢{... }¨⍳⍵: return Z, sau khi áp dụng hàm sau cho các số 1để :
    • ⍵∘{... }V/,Z=⍕⍵-1: cho mỗi phần tử Zbằng giá trị của nút trước đó:
      • ⍵∘{... }⍺/⍺: cho nút hiện tại, N lần,
        • ⊃F[⍋+/¨|(F←V/⍨,Z=' ')-⊂⍺]: lấy không gian trống gần nhất với nút hiện tại,
        • (... ⌷Z)←⍕⍵: Và đặt khoảng trống đó vào Zgiá trị của nút hiện tại.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.