转换在循环内递归到迭代方法的简单递归方法

时间:2015-04-21 23:39:51

标签: java python recursion

前段时间,我正在研究编程问题(CCC)。我在过去的比赛中也遇到过类似的问题所以我决定问一下这个问题。问题基本上就是这个。

给你n个人和p个馅饼。

人们站成一排。

您必须在其中分发p个馅饼。你按顺序进行,每个人必须至少收到与他们之前一样多的棋子。每个人必须至少收到一块馅饼,不得留下任何馅饼。

您必须返回分发饼图的可能方式的数量。

我设法创建了以下递归解决方案,但以下输入需要太长时间(超过5秒):

120件,20人 - > 97132873

250件,130人 - > 1844349560

我的解决方案:

import java.io.*;

public class Main
{
  int pieces, people;
  int combinations = 0;

  public void calculate (int person, int piecesLeft, int prev)
  {
    if (person == people)
    {
        if (piecesLeft == 0)
            combinations++;              
    }
    else
    {
        for (int x = prev ; (x * (people - person)) <= piecesLeft ; x++)
        {
            calculate (person + 1, piecesLeft - x, x);
        }
    }
  }


  public static void main (String[] args) throws Exception
  {
    Main m = new Main ();
    BufferedReader in = new BufferedReader (new InputStreamReader (System.in));
    //m.pieces = Integer.parseInt (in.readLine ());
    //m.people = Integer.parseInt (in.readLine ());
    m.pieces=250;
    m.people=130;
    if (m.people == m.pieces)
        System.out.println (1);
    else if (m.people == 1)
        System.out.println (1);
    else
    {
        m.calculate (0, m.pieces, 1);
        System.out.println (m.combinations);
    }
  }
}

我从非官方的解决方案中找到了以下python解决方案,根据我的理解,它基本上创建了一个已经遇到的值的数组。

visited = []
def pi(n,k,min):
if visited [n][k][min] == 0:       
    if n == k:
        visited[n][k][min] = 1
    elif k == 1:
        visited[n][k][min] = 1
    else:
        t = 0
        for i in range (min, (n / k)+1):
            t = t + pi(n-i, k-1, i)
        visited[n][k][min] = t
return visited[n][k][min]


file = open("j5.10.in", "r")
n = int(file.readline())
k = int(file.readline())

for i in range(n+1):
x = []
for j in range(k+1):
    t = []
    for kk in range(n+1):
        t.append (0)
    x.append(t)
visited.append(x)

print pi(n,k,1)

我想要做的是从其中任何一个中做出迭代解决方案,但我不知道该怎么做。根据我的理解,可能没有巨大的速度差异,但是对于更大的情况,它将允许我避免堆栈溢出。

1 个答案:

答案 0 :(得分:1)

第二个解决方案是memoized ... visited数组记录已经计算过的值。将memoized递归转换为(某种)迭代解决方案的技巧是循环通过较小的情况来填充memo数组。您可以丢弃较小案例的结果(无论如何它们都将存储在备忘录数组中)。然后,当你最终计算出你想要的那个时,它将立即使用备忘录数组,无需额外的计算。

如果您真的想从头开始构建迭代解决方案,那么您必须弄清楚以前需要存储的案例才能构建下一个案例。例如,要计算阶乘,使用循环,您只需要在内存中存储一​​个值。在硬币面额为1美分,5美分和10美分的变更问题中,您只需要保存前十个项目来构建下一个项目。在某些情况下,您需要知道所有先前的值才能构建下一个值。一旦你知道了,内存结构应该清楚,那么程序逻辑就会变得清晰。