Python递归算法不适用于大值 – C程序有效

我想为
this question写一个回溯解决方案,要求找到总和给定n的最明显的奇数.

我把这个Python代码整合在一起:

import sys
sys.setrecursionlimit(10000) 


stop = False
def solve(n, used, current_sum):
    global stop
    if stop:
        return

    if current_sum == n:
        print(used)
        stop = True
        return

    start = 1 if len(used) == 0 else (used[-1] + 2)
    for i in range(start, n + 1, 2):
        if current_sum + i <= n and not stop:
            used.append(i)
            solve(n, used, current_sum + i)
            used.pop()
        else:
            return

solve(100000000, [], 0)

遗憾的是,它不会为我打印任何内容.据我所知,如果有条件,它永远不会达到.如果我在每一步打印current_sum,当整个程序退出没有错误时,它似乎停在16000000左右.

我试过增加递归限制,没有运气.

我在Windows 8.1下在Idle和Eclipse上测试了它,在Python 3.4中,64位.我有16 GB的RAM.

如果我减少n,那么我得到一个解决方案(例如删除一个零).

这对我来说没有意义,所以我想看看我是否有更好的运气C.我在C中攻击了这个:

int sol[100000];
bool done = false;
void solve(int n, int k, int sum)
{
    if (done)
        return;

    if (sum == n)
    {
        done = true;
        for (int i = 0; i < k; ++i)
        {
            printf("%d ", sol[i]);
        }
        printf("\n");
        return;
    }

    int start = 1;
    if (k > 0)
        start = sol[k - 1] + 2;
    for (int i = start; i <= n; i += 2)
        if (sum + i <= n && !done)
        {
            sol[k] = i;
            solve(n, k + 1, sum + i);
        }
        else
            return;
}

int main()
{
    solve(100000000, 0, 0);

    return 0;
}

即使我添加另一个零,哪个效果很好!

与Python有什么关系?我如何才能使这个值适用于大值?

较低值的执行时间与C代码相当,它只是让我退出更高的值.

最佳答案

What is the deal with Python and how can I get this working for large
values as well?

我重写了你的代码以使它工作.增加n参数时,需要调整递归深度.我使用Python 2.7.6.我们的想法是和你编写的C代码一样,传递的第二个参数是整数,而不是列表.

import sys
sys.setrecursionlimit(100000) 

sol = []
stop = False

def solve(n, k, current_sum):
    global stop

    if stop:
        return

    if current_sum == n:
    stop = True
    for i in xrange(0, k, 1):
            print(sol[i]),
    print
        return

    start = 1 if len(sol) == 0 else (sol[k-1] + 2)
    for i in xrange(start, n + 1, 2):
        if current_sum + i <= n and not stop:
        sol.append(0)
        sol[k] = i
            solve(n, k + 1, current_sum + i)
        else:
            return

solve(100000000, 0, 0)

讨论这个问题

我试着读你编写的python代码的内存使用情况.我必须设置n = 100.000才能获得370 MB的结果.添加0使我的操作系统终止程序. (在Mac OS X上,我收到内存错误).

这是我在Linux上使用的代码:

import os
import sys

sys.setrecursionlimit(100000)


_proc_status = '/proc/%d/status' % os.getpid()

_scale = {'kB': 1024.0, 'mB': 1024.0*1024.0,
          'KB': 1024.0, 'MB': 1024.0*1024.0}

def _VmB(VmKey):
    '''Private.
    '''
    global _proc_status, _scale
     # get pseudo file  /proc/<pid>/status
    try:
        t = open(_proc_status)
        v = t.read()
        t.close()
    except:
        return 0.0  # non-Linux?
     # get VmKey line e.g. 'VmRSS:  9999  kB\n ...'
    i = v.index(VmKey)
    v = v[i:].split(None, 3)  # whitespace
    if len(v) < 3:
        return 0.0  # invalid format?
     # convert Vm value to bytes
    return float(v[1]) * _scale[v[2]]

def memory(since=0.0):
    '''Return memory usage in bytes.
    '''
    return _VmB('VmSize:') - since


stop = False
def solve(n, used, current_sum):
    global stop

    if stop:
        return

    if current_sum == n:
        print(used)
        stop = True
        return

    start = 1 if len(used) == 0 else (used[-1] + 2)
    for i in range(start, n + 1, 2):
        if current_sum + i <= n and not stop:
            used.append(i)
            solve(n, used, current_sum + i)
            used.pop()
        else:
            return

m0 = memory()
solve(100000, [], 0)
m1 = memory(m0)
print(m1/(1024*1024))

与此结果相比,我编写的改进(更正)代码仅使用4 MB,参数n设置为100.000.000.这确实是一个巨大的差异.

我不确定为什么会这样.特别是你有一个包含递归调用的循环(所以你可以从同一个分支中多次递归调用).

如果你坚持使用递归调用,那么也许你想重新设计你的程序.具有记忆功能的递归调用可能比情况下的循环更快.见this link for example.

点赞