日益壮大的曼哈顿Ameobas


11

*** ameoba图****是一类树,其所有节点的值都从0到某个非负整数N,并且任何值x <N的特定节点都连接到x + 1 值x +的不同节点1。

N = 3的Ameoba图(表示为A 3

变形虫3

请注意,不允许2共享3的任何一个。正好三个3必须分别属于“ 2”。

挑战

您的任务是通过贪婪地最小化节点之间的曼哈顿距离,在二维网格中归纳“增长”这些变形虫图:

  • 基本情况:0仅仅是图形0
  • 感应步骤:N + 1是通过迭代地将新的N + 1级值的节点尽可能接近的N个值中的节点现有A产生Ñ结构。(由于最接近的位置可能已经被填充,因此只能尽可能地靠近。)

对于归纳步​​骤,必须遵循的一般步骤是:

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的任何事物都太过分了。感谢MartinBü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 MB文件或类似的内容?A10是第一个拥有超过一百万个字符的变形虫。
isaacg 2014年

@MartinBüttner我已经做了8个极限,大约5万个节点。仍然很多,但希望可以管理。

Answers:


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分钟。

为了快速分解我的算法:

我正在使用两个查询表fg。第一个只是包含非空单元格的稀疏映射。后者是一个列表,其中包含每个单元格值的所有坐标对(我想我什至不需要在这里跟踪旧坐标对)。我正在遍历坐标g以扩展上一次迭代的每个单元格。为此,我遍历了曼哈顿的距离,为每个距离创建所有可能的向量,并检查结果单元格是否仍然为空(在这种情况下,我将其填充)。重复直到创建了足够的新单元格。

完成后,我在中找到最小和最大坐标,g并创建一个合适的网格,通过查找中的单元格将其填充f。其余的只是将所有内容连接到带有换行符的单个字符串中。


5

C- 309305301275字节

h,时间太长了……如果只有一个可以键入#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(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}¨⍳⍵}⎕

性能特征:是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,(如果输入为0return,0则创建图),但是0::0(尝试一下,0如果失败则返回)较短。)
  • M←⌈4×.5*⍨3÷⍨+/!⍳⍵:假设输出是一个粗糙的圆(此方法可行),将阶乘从1(=输出面积)相加,除以3(足够接近pi),取平方根(输出给定半径),再乘以4,并采取天花板。这提供了两倍的圆直径,因此输出适合剩余空间。将此存储在中M
  • V←,⍳⍴Z←' '⍴⍨2/M:制作一个M×M的空格矩阵并将其存储在中Z。这将保留输出。将所有元素的坐标列表存储在中V
  • Z[G;G←⌈M÷2]←'0':将的中间元素设置Z0
  • Z⊢{... }¨⍳⍵:返回Z,使用下列的函数的数字后1
    • ⍵∘{... }V/,Z=⍕⍵-1:对于每个Z具有前一个节点值的元素:
      • ⍵∘{... }⍺/⍺:对于当前节点,N次,
        • ⊃F[⍋+/¨|(F←V/⍨,Z=' ')-⊂⍺]:获取最接近当前节点的可用空间,
        • (... ⌷Z)←⍕⍵:并将该空间设置Z为当前节点的值。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.