Windows版Pythonの再帰呼び出し制限
CodeIQで出題された「アッカーマンの呪い」をPythonで解いた。アッカーマン関数のA(4,1)を求めろという問題で、メモ化だけして再帰で書くと、次のようになる。
memo = {} def A(m,n): if (m,n) not in memo: memo[(m,n)] = ( n+1 if m==0 else A(m-1,1) if n==0 else A(m-1,A(m,n-1)) ) return memo[(m,n)] def solve(): print A(2,1) print A(2,2) print A(3,4) print A(4,1)
普通に
solve()
と呼び出すと
RuntimeError: maximum recursion depth exceeded
になる。
出題者の解説にあるように、
sys.setrecursionlimit(1024*1024)
で再帰呼び出しの深さ制限を変更できるけど、Pythonのスタックサイズが足りないらしく、Pythonが不正終了する。Windowsの場合、新しく作成されるスタックのサイズを
thread.stack_size(128*1024*1024)
で変更できる。
このプログラムで、A(4,1)が計算できた。
import sys, threading, thread memo = {} def A(m,n): if (m,n) not in memo: memo[(m,n)] = ( n+1 if m==0 else A(m-1,1) if n==0 else A(m-1,A(m,n-1)) ) return memo[(m,n)] def solve(): print A(2,1) print A(2,2) print A(3,4) print A(4,1) solve() sys.setrecursionlimit(1024*1024) thread.stack_size(128*1024*1024) threading.Thread(target=solve).start()