无限猴子定理:超出最大递归深度

时间:2014-09-27 19:19:05

标签: python recursion runtime-error

我试图解决无限猴子定理,这是我在网上遇到的编程任务的一部分。

问题陈述是:

  

该定理指出,猴子在打字机键盘上随机敲击键无限时间几乎肯定会键入给定的文本,例如威廉·莎士比亚的全集。好吧,假设我们用Python函数替换猴子。你认为Python函数生成莎士比亚的一个句子需要多长时间?我们要拍的句子是:“它就像狡猾的人一样”

我试图看a)是否可以生成字符串b)生成字符串后迭代次数

我已经将递归限制设置为10000,查看之前的SO问题,但我仍然得到达到最大递归深度的运行时错误。

我仍然在寻找python的方法。我希望看到有关如何以更好的方式做到这一点的建议,而不会遇到递归深度问题。

到目前为止,这是我的代码:

import random
import sys
alphabet=['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',' ']
quote="methinks  it is like a weasel"
msg='cont'
count=0

sys.setrecursionlimit(10000)

def generate(msg):
    sentence=''
    while len(sentence)!=27:
        #random.choice() prints a random element from list 'alphabet'
        sentence=sentence+random.choice(alphabet)
    if msg=='cont':
        verify(sentence)

def verify(msg2):
    global count
    if msg2.find(quote)==-1:
        count+=1
        generate('cont')

    else:
        print 'sentence is ',msg2 ,'count is',count

if __name__ == '__main__':
    generate(msg)

4 个答案:

答案 0 :(得分:6)

这是一个在做之前最好先思考的情况。如果我们忽略大写和标点符号,则您的字符串由28个字符组成,每个字符原则上可以是字母表中的26个字母或空格中的任何一个。组合的数量是27 28 ,恰好是11972515182562019788602740026717047105681.如果你可以枚举每秒十亿次猜测,27 28 / 1E9(尝试/秒)/ 3600(秒/小时)/ 24(小时/天)/ 365.25(天/年)/ 14E9(年龄/当前宇宙年龄) => 27099008032844.297。好消息是你可能在任何时候偶然发现答案,所以预期的时间只是当前宇宙年龄的27万亿倍的一半。

吹掉堆栈是你遇到的最少问题。

它被称为无限猴子定理的原因是你可以除以可以并行处理它的猴子的数量,如果那是无穷大,那么求解时间就变成每猴子产生猜测的时间量,十亿分之一一秒钟。

答案 1 :(得分:2)

最好不要在猴子没有写莎士比亚的情况下,从verify()(反之亦然)调用generate()

如果导致超出递归深度的原因导致两个函数重复相互调用而不返回。

您可以简单地检查您是否使用迭代方法生成了句子,而不是使用递归。例如,有一个循环,它接受一个随机句子,然后检查它是否与你所需的句子匹配,如果是,则输出它尝试的次数(如果没有循环回到开始)。

答案 2 :(得分:0)

done = False
count = 1
while not done:
    msg = generate()
    if verify(msg):
        print 'success, count = ', count
        done = True
    count += 1

答案 3 :(得分:0)

可能类似以下内容。它运行在CPython 2上。[67],CPython 3. [01234],pypy 2.4.0,pypy3 2.3.1和jython 2.7b3。使用--production运行需要很长时间,即使是在pypy或pypy3上运行。

#!/usr/local/cpython-3.4/bin/python

'''Infinite monkeys randomly typing Shakespeare (or one monkey randomly typing Shakespeare very fast'''

# pylint: disable=superfluous-parens
# superfluous-parens: Parentheses are good for clarity and portability

import sys
import itertools


def generate(alphabet, desired_string, divisor):
    '''Generate matches'''
    desired_tuple = tuple(desired_string)
    num_possibilities = len(alphabet) ** len(desired_string)
    for candidateno, candidate_tuple in enumerate(itertools.product(alphabet, repeat=len(desired_string))):
        if candidateno % divisor == 0:
            sys.stderr.write('checking candidateno {0} ({1}%)\n'.format(candidateno, candidateno * 100.0 / num_possibilities))
        if candidate_tuple == desired_tuple:
            match = ''.join(candidate_tuple)
            yield match


def usage(retval):
    '''Output a usage message'''
    sys.stderr.write('Usage: {0} --production\n'.format(sys.argv[0]))
    sys.exit(retval)


def print_them(alphabet, quote, divisor):
    '''Print the matches'''
    for matchno, match in enumerate(generate(alphabet, quote, divisor)):
        print('{0} {1}'.format(matchno, match))


def main():
    '''Main function'''
    production = False

    while sys.argv[1:]:
        if sys.argv[1] == '--production':
            production = True
        elif sys.argv[1] in ['--help', '-h']:
            usage(0)
        else:
            sys.stderr.write('{0}: Unrecognized option: {1}\n'.format(sys.argv[0], sys.argv[1]))
            usage(1)

    if production:
        print_them(alphabet='abcdefghijklmnopqrstuvwxyz ', quote='methinks it is like a weasel', divisor=10000)
    else:
        print_them(alphabet='abcdef', quote='cab', divisor=10)


main()