阿克曼函数


35

Ackermann函数是非原始递归的全部可计算函数中最简单的例子之一。

我们将使用以下A(m,n)两个非负整数的定义:

A(0,n) = n+1
A(m,0) = A(m-1,1)
A(m,n) = A(m-1,A(m,n-1))

您可以实施

  • 一个以两个整数作为输入,返回一个整数的命名或匿名函数,或者
  • 一个程序,在STDIN上使用两个以空格或换行符分隔的整数,并将结果打印到STDOUT。

如果存在库,则不能使用库中的Ackermann函数或超幂函数,但是可以使用任何其他库中的任何其他函数。允许定期取幂。

您的函数必须能够A(m,n)在不到一分钟的时间内找到m≤3和n≤10 的值。从理论上讲,它必须至少终止于任何其他输入:给定无限堆栈空间,本机Bigint类型以及任意长时间,它将返回答案。编辑:如果您的语言的默认递归深度过于严格,则可以重新配置它而无需花费任何字符。

字符数最少的提交将获胜。

以下是一些值,以检查您的答案:

  A  | n=0     1     2     3     4     5     6     7     8     9    10
-----+-----------------------------------------------------------------
 m=0 |   1     2     3     4     5     6     7     8     9    10    11
   1 |   2     3     4     5     6     7     8     9    10    11    12
   2 |   3     5     7     9    11    13    15    17    19    21    23
   3 |   5    13    29    61   125   253   509  1021  2045  4093  8189
   4 |  13 65533   big   really big...

15
以前没有问过这个吗?
卡尔文的爱好2014年

9
我认为制作此最快的代码
Sp3000 2014年

22
拒绝投票,因为这里没有挑战。显而易见的答案-仅根据其定义天真地实现该功能-始终将是最佳答案。因此,问题只是“在阿克曼函数的明显表达中,哪种语言的字符数最少?” 真正的赢家是编程语言,而不是使用明显的程序的人。
David Richerby

1
如果我的语言的递归限制太低而无法A(3,8)像其他语言一样天真地计算出来呢?在这些情况下,我是否必须提出非递归解决方案,还是可以仅“假定无限堆栈空间”?我相当确定,它会在一分钟内终止。
马丁·恩德2014年

5
@DavidRicherby“显而易见的答案始终是最好的答案。” 并非所有语言都如此。我只用我的母语写了一个例子,这让我感到有些肮脏,但是表达阿克曼的方式有多种,通过使用某些事实,您可以节省很多钱。这是我挑战的意图。
algorithmhark

Answers:


7

佩斯 19

DaGHR?atG?aGtHH1GhH

定义a,用作Ackermann函数。请注意,这需要的递归深度比直到今天才允许使用的官方pyth编译器高a 3 10,因此我增加了递归深度。这不是对语言的更改,只是对编译器的更改。

测试:

$ time pyth -c "DaGHR?atG?aGtHH1GhH           ;a 3 10"
8189

real    0m0.092s
user    0m0.088s
sys     0m0.000s

说明:

DaGH                     def a(G,H):
    R                    return
    ?          G                (if G:
     atG                              (a(G-1,
        ?    H                               (if H:
         aGtH                                      a(G,H-1)
              1                               else:1)
                hH               else:H+1)

本质上,它首先G确定是否递归或返回H + 1 的真值。如果递归,则第一个参数始终为G-1,它取决于H是否要a(G,H-1)用作第二个参数或用作第二个参数的真值1


在现代的Pyth中(我认为这是在挑战之后添加的),我认为您可以或多或少地更改DaGHRto Mato g。(是否有?变更论据的顺序?)
Lynn 2015年

@Mauris是的,您可以M改用,是的,?参数顺序已更改。现在是条件,正确,错误。这是真的,条件,是错误的。
isaacg 2015年

@Lynn Fun Pyth历史事实:这个问题实际上影响了isaacg更改(至少)有关Pyth的两件事:递归限制更改为M
FryAmTheEggman

23

哈斯克尔(35)

0%n=1+n
m%n=iterate((m-1)%)1!!(n+1)

这定义了运算符功能%

注意到非零m%naackerman函数在哪里)m(m-1)%应用了n+1时间,这才起作用1。例如,3%2被定义为2%(3%1)2%(2%(3%0)),这是2%(2%(2%1))


太糟糕了,我不能因为优先0%n而无法使用n+1
骄傲的haskeller 2014年


哇,这已经错了很长时间了,没有人注意到我,包括我自己?辛苦了 所以看来我错误地复制了答案的第一版,这是错误的,可能是由于错误,或者是因为我认为它有效。
骄傲的haskeller

12

高尔夫脚本(30)

{1$1>{1\){1$(\A}*\;}{+)}if}:A;

在线演示

如果没有1>(在特殊情况下A(1, n)),则需要9分钟才能A(3, 10)在我测试过的计算机上进行计算。在这种特殊情况下,它的速度足以使在线演示花费不到10秒的时间。

请注意,这不是该定义的幼稚翻译。递归深度由限制m

解剖

{             # Function boilerplate
  1$          # Get a copy of m: stack holds m n m
  1>{         # (Optimisation): if m is greater than 1
    1         #   Take this as the value of A(m, -1)
    \){       #   Repeat n+1 times:
              #     Stack: m A(m, i-1)
      1$(\    #     Stack: m m-1 A(m, i-1)
      A       #     Stack: m A(m, i)
    }*
    \;        #   Lose that unwanted copy of m
  }{          # Else
    +)        #   A(m in {0, 1}, n) = m + n + 1
  }if
}:A;          # Function boilerplate

在CJam中,您不需要1>。删除(并更改if?)后,3 10 A使用在线解释器进行计算需要110秒,而使用Java解释器则需要6秒。
丹尼斯


6

的JavaScript,ES6,41个 34字节

f=(m,n)=>m?f(m-1,!n||f(m,n-1)):n+1

在最新的Firefox控制台运行此,它会创建一个调用的函数f,你可以用不同的值调用mn

f(3,2) // returns 29

要么

在最新的Firefox中尝试以下代码

f=(m,n)=>m?f(m-1,!n||f(m,n-1)):n+1

B.onclick=_=>alert(f(+M.value, +N.value))
#M,#N{max-width:15px;border: 1px solid;border-width:0 0 1px 0}
<div>f(<input id=M />,<input id=N />)</div><br><button id=B>Evaluate</button>


在Chrome中以0,1进行测试不会产生任何结果。
Nzall 2014年

3
请阅读,由于ES6
Optimizer

哇...我们有4个几乎相同的JS解决方案,全部为34个字节。我以前从未见过。
ETHproductions 2015年

6

蟒2.7.8 - 80,54,48,46 45

A=lambda m,n:m and A(m-1,n<1or A(m,n-1))or-~n

(归功于xnor!)

更具可读性,但多了1个字符:

A=lambda m,n:n+(m<1or A(m-1,n<1or A(m,n-1))-n)

并非我必须设置sys.setrecursionlimit(10000)才能获得的结果A(3,10)。由于递归深度的急剧增加,使用逻辑索引进行的进一步打高尔夫球没有用。


我在上收到语法错误1else。起始字母e会给解析器带来麻烦,因为数字可以像这样写1e3
xnor

保存了一些字符切换到and/orA=lambda m,n:m and A(m-1,n<1or A(m,n-1))or-~n
xnor 2014年

@xnor:谢谢小费!请参阅此讨论以获取解析问题。Python 2.7.8接受1else,大多数其他版本不接受。
Falko 2014年

感谢有关的指示1else; 它可以让我在这里和其他地方挤出一个字符。但是该死的是特定于版本的!Python 2.7.4不允许使用它。您是否正在使用带有2.7.8的在线版本,还是需要下载?
xnor

@xnor:这是一个脱机安装。ideone.com也无法解析1else
Falko 2014年

6

J-26个字符

($:^:(<:@[`]`1:)^:(0<[)>:)

Ackermann还有一个更实用的替代定义:

Ack 0 n = n+1
Ack m n = Iter (Ack (m-1)) n
Iter f 0 = f 1
Iter f n = f (Iter f (n-1))

碰巧这种Iter情况很容易用J编写,因为J有一种传递m-1to 的方法,Ack并且还定义了to的初始值Iter。1用爆炸解释:

(                      >:)  NB. increment n
                ^:(0<[)     NB. if m=0, do nothing to n+1; else:
   ^:                       NB. iterate...
($:                      )  NB.   self ($: is recursion)
     (<:@[     )            NB.   with left arg m-1
          `]                NB.   n+1 times
            `1:             NB.   starting on 1

这依赖于J所谓的gerund形式,^:基本上是一种以默认(无点)方式对所有范围进行更多控制的方法。

在REPL:

   3 ($:^:(<:@[`]`1:)^:(0<[)>:) 3
61
   ack =: ($:^:(<:@[`]`1:)^:(0<[)>:)
   (i.4) ack"0 table (i.11)
+-----+------------------------------------------+
|ack"0|0  1  2  3   4   5   6    7    8    9   10|
+-----+------------------------------------------+
|0    |1  2  3  4   5   6   7    8    9   10   11|
|1    |2  3  4  5   6   7   8    9   10   11   12|
|2    |3  5  7  9  11  13  15   17   19   21   23|
|3    |5 13 29 61 125 253 509 1021 2045 4093 8189|
+-----+------------------------------------------+
   6!:2 '3 ($:^:(<:@[`]`1:)^:(0<[)>:) 10'  NB. snugly fits in a minute
58.5831

我们需要ack按名称定义才能将其放置在表格中,因为它$:是一种可怕的丑陋的野兽,会猛烈抨击任何试图理解它的人。它是自我参照,自我定义为包含自我的最大动词短语。table是副词,所以如果有机会,它很想成为动词短语的一部分,因此必须$:使用命名的定义才能使用它。


编辑:24个字符?

多年后,我找到了一个解决方案,该解决方案要短两个字符。

(0&<~(<:@#~$:/@,1:^:)>:)

但是,它要慢很多:3 ack 8在我的机器上花费一分钟以上。这是因为(1)I使用折叠/代替迭代的,所以Ĵ大概必须记住比平时更多的东西,和(2),同时0&<~执行相同的计算(0<[),它实际上被执行n+1服用递归步骤之前调用时m ack n- 0&<发生是幂等的,因此它不会破坏计算,但n会快速变大并且ack具有高度递归性。

我怀疑功能更强大的计算机能否在一分钟内推送新代码,因为这是一台可以3 ack 10在不到15秒的时间内找到旧代码的计算机。


5

C-41个字节

没什么-很小的限制意味着通过天真地遵循函数定义,可以在不到1秒的时间内计算出所有所需的值。

A(m,n){return!m?n+1:A(m-1,n?A(m,n-1):1);}


int main()
{
    int m,n;
    for(m = 0; m <= 3; m++)
    for(n = 0; n <= 10; n++)
    printf("%d %d %d\n", m,n,A(m,n));
    return 0;
}

5

Javascript ES6(34)

a=(m,n)=>m?a(m-1,n?a(m,n-1):1):n+1

实现方式:

a=(m,n)=>m?a(m-1,n?a(m,n-1):1):n+1
td[colspan="2"] input{width: 100%;}
<table><tbody><tr><td>m=</td><td><input id="m" type="number" value="0" /></td></tr><tr><td>n=</td><td><input id="n" type="number" value="0" /></td></tr><tr><td colspan="2"><input type="button" value="Calculate!" onclick="document.getElementById('out').value=a(document.getElementById('m').value, document.getElementById('n').value)" /></td></tr><tr><td colspan="2"><input id="out" disabled="disabled" type="text" /></td></tr></tbody></table>


4

JavaScript(ES6)-34

A=(m,n)=>m?A(m-1,!n||A(m,n-1)):n+1

并进行测试:

> A=(m,n)=>m?A(m-1,!n||A(m,n-1)):n+1;s=new Date().getTime();console.log(A(3,10),(new Date().getTime() - s)/1000)
8189 16.441

3

辅酶40

nat_rec _ S(fun _ b n=>nat_iter(S n)b 1)

这是type的函数nat -> nat -> nat。由于Coq仅允许构造全部函数,因此它也可以作为阿克曼复发的充分依据的正式证明。

演示:

Welcome to Coq 8.4pl6 (November 2015)

Coq < Compute nat_rec _ S(fun _ b n=>nat_iter(S n)b 1) 3 10.
     = 8189
     : nat

注意:此挑战后发布的Coq 8.5已重命名nat_iterNat.iter



2

Mathematica,46个字节

0~a~n_:=n+1
m_~a~n_:=a[m-1,If[n<1,1,a[m,n-1]]]

大约需要一分钟的时间a[3,10]。请注意,Mathematica的默认递归限制太小了a[3,8](至少在我的机器上),但可以通过配置来解决

$RecursionLimit = Infinity

1
哇,您是说JS比Mathematica快25倍以上吗?
Optimizer

@Optimizer至少在递归方面……我想部分原因是,它每次必须弄清楚要使用哪个定义,并且If成为函数的速度甚至更慢。
Martin Ender 2014年

1
使用备忘录时,它需要0.07秒。即m_~a~n_:=m~a~n=...
马克·阿德勒

@MarkAdler这是在Mathematica中进行记忆的一种非常好的方法!
马丁·恩德

2

带有lambdas的Javascript,34

A=(m,n)=>m?A(m-1,n?A(m,n-1):1):n+1

一个典型的答案,不能缩短任何时间。


2

Haskell,48个 44个字符(列表中为36个)

尽管不如其他Haskell解决方案那么短,但该解决方案值得注意,因为它将Ackermann函数表示为一个无限列表,我认为这很简洁。结果是一个无限列表(无限列表),因此在位置[m,n]处拥有值A(m,n)

无限列表本身:

iterate(tail.(`iterate`1).(!!))[1..]

作为功​​能(符合规范):

i=iterate;m%n=i(tail.(`i`1).(!!))[1..]!!m!!n

该公式是通过观察Ackermann函数的一般情况/通用情况得出的,即使用左上方的值作为上一行中的索引。此递归的基本情况(即,一行的最左列,即A(m,0))将使用上面一行中的第二个最左值。为基础案例递归是A(0,N)= N + 1的情况下,即,第一行是[1..]

因此,我们得到

let a0 = [1..]
let a1 = tail $ iterate (a0 !!) 1  -- 'tail' because iterate starts by applying
let a2 = tail $ iterate (a1 !!) 1  -- the function 0 times
-- etc

然后,我们仅基于该模式添加另一级别的迭代,并进行一些毫无意义的操作


您可以将别名iterate命名为单个字母,即i=iterate;ack=i ...
2014年

@proudhaskeller哦,是的,没想到。谢谢!也借用您的操作员名称使用。
FireFly 2014年

2

Tiny Lisp,70(非竞赛类)

由于语言比问题新,因此这会失去竞争,并且(A 3 10)由于堆栈溢出,它也无法按问题中的要求成功运行。

(d A(q((m n)(i m(i n(A(s m 1)(A m(s n 1)))(A(s m 1)1))(s n(s 0 1))))))

这定义了一个A计算阿克曼函数的函数。格式:

(d A
   (q( (m n)
       (i m
          (i n
             (A (s m 1)
                (A m
                   (s n 1)
                 )
              ) 
             (A (s m 1)
                1
              )
           )
          (s n
             (s 0 1)
           )
        )
    ) )
 )

我们在这里使用所有内置宏(d(定义),q(引用)和i(如果))和一个内置函数(s–减)。

i 当条件为数字> 0时执行其真部分(否则为假部分),因此我们在这里不必进行显式比较。

s是唯一可用的算术运算,我们使用它的n-1/ m-1,以及作为(s n (s 0 1))n+1

Tiny Lisp正在使用尾部递归优化,但这仅对A结果中的外部调用有所帮助,而不对A(m, n-1)用于参数的调用有所帮助。

使用在JVM上的Ceylon中实现的lisp小型实现,它可以工作到(A 3 5) = 253,但是在尝试(A 2 125)直接计算时似乎崩溃了(应该给出相同的结果)。如果在计算之后(A 3 4) = 125,JVM似乎必须对功能进行足够的优化以在我的解释器中内联一些中间函数调用,从而允许更大的递归深度。奇怪。

参考实现起床(A 3 5) = 253(A 2 163) = 329,但没有成功(A 2 164),因此,甚至更少(A 3 6) = (A 2 253)


除空格和括号外,这可能是有竞争力的;)
cat

2

围棋,260个 243 240 122字节

我没有看到这个问题允许匿名函数。

远没有竞争力,但我正在学习这种语言,所以我想对其进行测试。

func (m,n int)int{r:=0
switch{case m==0&&n!=0:r=n+1
case m!=0&&n==0:r=a(m-1,1)
case m!=0&&n!=0:r=a(m-1,a(m,n-1))}
return r}

使用它go run ack.go,然后提供两个数字,mn。如果m> 4或n> 30,则执行时间可能超过半分钟。

m=3 n=11

$ time go run ack
16381
real    0m1.434s
user    0m1.432s
sys     0m0.004s

编辑:保存共有17个字节通过切换到switch过度if/else和DOT-进口


1
您可以做得更好!switch 0 {case m:r=n+1 case n:r=a(m-1,1) default:r=a(m-1,a(m,n-1))}Go的switch声明非常灵活!
EMBLEM

@EMBLEM谢谢,它已经这么长时间,因为我已经写了走行的,但我很高兴看到有关于其他的Go-球手:d

1

Haskell:81 69字节

a::Int->Int->Int
a 0 n=n+1
a m 0=a (m-1) 1
a m n=a (m-1) a m (n-1)

a 3 10 大约需要45秒。


1
这是代码高尔夫球,所以您应该尝试使用最短的代码。例如,删除不必要的空格和显式类型
骄傲的haskeller 2014年

您也错过了第四行的括号
骄傲的haskeller 2014年


1

(非竞争)UGL31 30字节

iiRuldr%l%lR$d%rd:u%d:%+uRu:ro

输入用换行符分隔。

在线尝试!

(它已在解释器中作为标准示例实现。)



1

R- 54 52

我以此为借口试图绕过R,所以这确实做得不好:)

a=function(m,n)"if"(m,a(m-1,"if"(n,a(m,n-1),1)),n+1)

运行示例

> a(3,8)
[1] 2045

除此以外,我都会堆栈溢出

T-SQL- 222

我以为我也会尝试让T-SQL做到这一点。使用了另一种方法,因为在SQL中递归不是那么好。超过4,2的炸弹都会炸毁它。

DECLARE @m INT=4,@n INT=1;WITH R AS(SELECT 2 C, 1 X UNION ALL   SELECT POWER(2,C),X+1FROM R)SELECT IIF(@m=0,@n+1,IIF(@m=1,@n+2,IIF(@m=2,2*@n+3,IIF(@m=3,POWER(2,@n+3)-3,IIF(@m=4,(SELECT TOP(1)C FROM R WHERE x= @n+3)-3,-1)))))

对于您的R子提交,看起来好像不需要,{}尽管没有帮助堆栈溢出限制,因为R没有TCO ...
Giuseppe

@Giuseppe谢谢...在我的辩护中,我
才刚接触

1

brainfuck,90个字节

>>>>+>,>,<<[>[>[-[->>>+<<<]<[->+>>+<<<]>-[-<+>]>+>>>>>]<[->+>>]]<[>>+[-<<<+>>>]<<-]<<<]>>.

在线尝试!

假设实现具有任意大小的单元大小,并且IO为数字。如果您不介意使用负数单元,则为-6个字节。

如果您勾选正确的设置,则在链接的解释器中以3,8的时间在约30秒内完成。输入以\s 开头的输入数字,例如3,9is \3\9


1

Tcl,67个字节

proc tcl::mathfunc::A m\ n {expr {$m?A($m-1,$n?A($m,$n-1):1):$n+1}}

在线尝试!


Tcl,77字节

proc A m\ n {expr {$m?[A [expr $m-1] [expr {$n?[A $m [expr $n-1]]:1}]]:$n+1}}

在线尝试!

在联机编译器中,由于超时而无法运行,但是在本地Tcl解释器中,它运行良好。我分析了对A函数的每个根调用,以查看计算每个{m,n}待测对象对花费了多少时间:

m=0, n=0, A=1, time=3.5e-5 seconds
m=0, n=1, A=2, time=2e-6 seconds
m=0, n=2, A=3, time=8e-6 seconds
m=0, n=3, A=4, time=1e-6 seconds
m=0, n=4, A=5, time=2e-6 seconds
m=0, n=5, A=6, time=1e-6 seconds
m=0, n=6, A=7, time=1e-6 seconds
m=0, n=7, A=8, time=1e-6 seconds
m=0, n=8, A=9, time=1e-6 seconds
m=0, n=9, A=10, time=0.0 seconds
m=0, n=10, A=11, time=1e-6 seconds
m=1, n=0, A=2, time=4e-6 seconds
m=1, n=1, A=3, time=6e-6 seconds
m=1, n=2, A=4, time=1e-5 seconds
m=1, n=3, A=5, time=1.2e-5 seconds
m=1, n=4, A=6, time=1.5e-5 seconds
m=1, n=5, A=7, time=2e-5 seconds
m=1, n=6, A=8, time=2e-5 seconds
m=1, n=7, A=9, time=2.6e-5 seconds
m=1, n=8, A=10, time=3e-5 seconds
m=1, n=9, A=11, time=3e-5 seconds
m=1, n=10, A=12, time=3.3e-5 seconds
m=2, n=0, A=3, time=8e-6 seconds
m=2, n=1, A=5, time=2.2e-5 seconds
m=2, n=2, A=7, time=3.9e-5 seconds
m=2, n=3, A=9, time=6.3e-5 seconds
m=2, n=4, A=11, time=9.1e-5 seconds
m=2, n=5, A=13, time=0.000124 seconds
m=2, n=6, A=15, time=0.000163 seconds
m=2, n=7, A=17, time=0.000213 seconds
m=2, n=8, A=19, time=0.000262 seconds
m=2, n=9, A=21, time=0.000316 seconds
m=2, n=10, A=23, time=0.000377 seconds
m=3, n=0, A=5, time=2.2e-5 seconds
m=3, n=1, A=13, time=0.000145 seconds
m=3, n=2, A=29, time=0.000745 seconds
m=3, n=3, A=61, time=0.003345 seconds
m=3, n=4, A=125, time=0.015048 seconds
m=3, n=5, A=253, time=0.059836 seconds
m=3, n=6, A=509, time=0.241431 seconds
m=3, n=7, A=1021, time=0.971836 seconds
m=3, n=8, A=2045, time=3.908884 seconds
m=3, n=9, A=4093, time=15.926341 seconds
m=3, n=10, A=8189, time=63.734713 seconds

最后一对失败{m,n}={3,10},因为它花费了超过一分钟的时间。

对于的较高值m,将需要增加该recursionlimit值。


我将其缩短到65个字节,但它不能满足问题的要求“您的函数必须能够在不到一分钟的时间内找到m≤3和n≤10的A(m,n)的值。” 如果没有,{}它将在TIO上超时,并且不会对最后两个条目进行演示。

Tcl,65个字节

proc tcl::mathfunc::A m\ n {expr $m?A($m-1,$n?A($m,$n-1):1):$n+1}

在线尝试!


0

J:50

>:@]`(1$:~<:@[)`(<:@[$:[$:_1+])@.(0>.[:<:@#.,&*)M.

在不到一秒的时间内返回0 ... 3与0 ... 10:

   A=:>:@]`(1$:~<:@[)`(<:@[$:[$:_1+])@.(0>.[:<:@#.,&*)M.
   timespacex 'res=:(i.4) A"0 table (i.11)'
0.0336829 3.54035e6
   res
┌───┬──────────────────────────────────────────┐
│A"0│0  1  2  3   4   5   6    7    8    9   10│
├───┼──────────────────────────────────────────┤
│0  │1  2  3  4   5   6   7    8    9   10   11│
│1  │2  3  4  5   6   7   8    9   10   11   12│
│2  │3  5  7  9  11  13  15   17   19   21   23│
│3  │5 13 29 61 125 253 509 1021 2045 4093 8189│
└───┴──────────────────────────────────────────┘

PS:“ 0的作用是使A在每个单个元素上起作用,而不是在左右数组之间进行滚动,并产生长度错误。但是9 = 2 A 3则不需要它。



0

APL,31

{⍺=0:⍵+1⋄⍵=0:1∇⍨⍺-1⋄(⍺-1)∇⍺∇⍵-1}

非常简单。一次使用⍨字符可通过反转参数来保存一个字节。将m作为左参数,将n作为右参数。

TryAPL.org


0

Ruby,65岁

h,a={},->m,n{h[[m,n]]||=m<1?(n+1):(n<1?a[m-1,1]:a[m-1,a[m,n-1]])}

说明

这是问题描述中给出的算法的非常直接的翻译。

  • 输入作为lambda的参数。两个Integers的预期。
  • 为了提高速度并避免堆栈溢出错误,答案会记录在中Hash h。的||=操作者用于计算的以前未计算的值。

a[3,10] 在我的机器上大约需要0.1秒。

这是一个非高尔夫版本

h = {}
a = lambda do |m,n|
  h[[m,n]] ||= if m < 1 
    n + 1
  elsif n < 1
    a[m-1,1]
  else
    a[m-1,a[m,n-1]]
  end
end

a[3,10]在我的机器上抛出SystemStackError ...
TuxCrafting

高尔夫球:您可以更改m<1?(n+1):(n<1?a[m-1,1]:a[m-1,a[m,n-1]])m<1?n+1:a[m-1,n<1?1:a[m,n-1]]
Simply Beautiful

0

鼠标200299个 83字节

$Y1%j:j.0=m:2%k:k.0=n:m.n.>[k.1+!|m.n.<[#Y,j.1-,1;|m.n.*0=[#Y,j.1-,#Y,j.,k.1+;;]]]@

0

Java,274个字节

import java.math.*;class a{BigInteger A(BigInteger b,BigInteger B){if(b.equals(BigInteger.ZERO))return B.add(BigInteger.ONE);if(B.equals(BigInteger.ZERO))return A(b.subtract(BigInteger.ONE),BigInteger.ONE);return A(b.subtract(BigInteger.ONE),A(b,B.subtract(BigInteger.ONE)));}}

它计算A(3,10)在几秒钟,并给予无限存储器和堆空间,它可以计算的任何组合bB只要结果是低于2 2147483647 -1。


我知道已经有一段时间了,但是您可以将其import java.math.*;BigInteger A(BigInteger b,BigInteger B){return b.equals(B.ZERO)?B.add(B.ONE):B.equals(B.ZERO)?A(b.subtract(B.ONE),B.ONE):A(b.subtract(B.ONE),A(b,B.subtract(B.ONE)));}
打成

0

锡兰,88 87 85

alias I=>Integer;I a(I m,I n)=>m<1then n+1else(n<1then a(m-1,1)else a(m-1,a(m,n-1)));

这是一个简单的实现。格式:

alias I => Integer;
I a(I m, I n) =>
        m < 1
        then n + 1
        else (n < 1
            then a(m - 1, 1)
            else a(m - 1, a(m, n - 1)));

别名只保存一个字节,没有它(用写Integer代替I),我们将得到86个字节。另外两个字节可以通过更换保存== 0< 1两倍。

使用的默认设置ceylon run,它最多可以使用A(3,12) = 32765(和A(4,0) = 13),但是A(3,13)(因此也可以A(4,1))将引发堆栈溢出错误。(A(3,12)大约需要5秒钟,A(3,11)在我的计算机上大约需要3 秒钟。)

使用ceylon run-js(即在node.js上运行编译为JavaScript的结果)的速度要慢得多(需要1分钟19 s A(3,10)),并且A(3, 11)在运行1后已经中断了“ 超出最大调用堆栈大小”(使用默认设置)最少30秒。


无需递归的锡兰228

另外,这是一个非递归版本(当然,更长一些,但是不受堆栈溢出的影响–有时可能会出现内存不足错误)。

import ceylon.collection{A=ArrayList}Integer a(Integer[2]r){value s=A{*r};value p=s.addAll;while(true){if(exists m=s.pop()){if(exists n=s.pop()){if(n<1){p([m+1]);}else if(m<1){p([n-1,1]);}else{p([n-1,n,m-1]);}}else{return m;}}}}

格式:

import ceylon.collection {
    A=ArrayList
}

Integer a(Integer[2] r) {
    value s = A { *r };
    value p = s.addAll;
    while (true) {
        if (exists m = s.pop()) {
            if (exists n = s.pop()) {
                if (n < 1) {
                    p([m + 1]);
                } else if (m < 1) {
                    p([n - 1, 1]);
                } else {
                    p([n - 1, n, m - 1]);
                }
            } else {
                // stack is empty
                return m;
            }
        }
    }
}

在我的计算机上,它比递归版本要慢得多:A(3,11)花费9.5秒,A(3,12)花费34秒,A(3,13)花费2:08分钟,A(3,14)花费8:25分钟。(我最初使用的是懒惰的可迭代版本,而不是我现在使用的元组,而同样的大小,它甚至慢得多)。

A(3,12)使用s.push而不是的版本要快一点(的时间为21秒)(但也要长一个字节)s.addAll,但是需要多次调用才能添加多个数字,因为每个数字只需要一个Integer。使用LinkedList而不是ArrayList要慢得多。

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.