简体   繁体   English

Python - 使用递归计算总可能性

[英]Python - Calculating total possibilities using recursion

I am trying to find the total possibilities of how to place 90 apples in 90 boxes.我试图找到如何在 90 个盒子中放置 90 个苹果的全部可能性。 Any amount of apples can be placed in one box (0 to 90 apples), but all apples have to be placed into boxes.任何数量的苹果都可以放在一个盒子里(0 到 90 个苹果),但所有的苹果都必须放在盒子里。 I used recursion but it took way too much time to complete the calculation.我使用了递归,但完成计算花费了太多时间。 I was only able to test my code with small amounts of apples and boxes.我只能用少量的苹果和盒子来测试我的代码。 Could anyone help me on reduce the time complexity of my code?任何人都可以帮助我降低代码的时间复杂度吗? Thanks in advance.提前致谢。

import math

boxes = 3
apples = 3

def possibilities(apples, boxes):
    if apples == 0:
        return 1
    if boxes == 0:
        return 0
    start_point = 0 if boxes > 1 else math.floor(apples/boxes)

    p = 0
    for n in range(start_point, apples+1):
        p += possibilities(apples-n, boxes-1)
    return p

t = possibilities(apples,boxes)
print(t)

The way I see it, the problem consists in finding the number of sorted list of max 90 elements which have a sum equal to 90.在我看来,问题在于找到总和等于 90 的最多 90 个元素的排序列表的数量。

There is a concept which is quite close to this and we call it the partitions of a number.有一个与此非常接近的概念,我们称之为数字的分区。

For example, the partitions of 4 are [4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1] .例如,4 的分区是[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]

After a bit of research I found this article which is relevant to your problem.经过一番研究,我发现这篇文章与您的问题有关。

As explained in there, the recursion method results in a very long calculation for large numbers, but...正如在那里解释的那样,递归方法会导致大量的计算时间很长,但是......

A much more efficient approach is via an approach called dynamic programming .一种更有效的方法是通过称为动态编程的方法。 Here we compute a function psum(n,k), which is the total number of n-partitions with largest component of k or smaller.这里我们计算一个函数 psum(n,k),它是具有最大分量 k 或更小的 n 分区的总数。 At any given stage we will have computed the values of psum(1,k), psum(2,k), psum(3,k), ..., psum(n,k) for some fixed k.在任何给定的阶段,我们都会为某个固定 k 计算 psum(1,k)、psum(2,k)、psum(3,k)、...、psum(n,k) 的值。 Given this vector of n values we compute the values for k+1 as follows:给定这个包含 n 个值的向量,我们计算 k+1 的值如下:

  • psum(i,k+1) = psum(i,k) + p(i,k) for any value i psum(i,k+1) = psum(i,k) + p(i,k) 对于任何值 i

  • But recall that p(i,k) = Σj p(ik,j) = psum(ik,k)但是回想一下 p(i,k) = Σj p(ik,j) = psum(ik,k)

  • So psum(i,k+1) = psum(i,k) + psum(ik,k)所以 psum(i,k+1) = psum(i,k) + psum(ik,k)

So with a little care we can reuse the vector of values and compute the values of psum(i,k) in a rolling value for successively greater values of k.因此,稍加注意,我们可以重用值向量,并在滚动值中计算 psum(i,k) 的值,以获得连续更大的 k 值。 Finally, we have a vector whose values are psum(i,n).最后,我们有一个向量,其值为 psum(i,n)。 The value psum(n,n) is the desired value p(n).值 psum(n,n) 是期望值 p(n)。 As an additional benefit we see that we have simultaneously computed the values of p(1), p(2), ..., p(n).作为额外的好处,我们看到我们同时计算了 p(1), p(2), ..., p(n) 的值。

Basically, if you keep the intermediate values in a list and use the recurrence presented in the article,基本上,如果您将中间值保留在列表中并使用文章中提供的循环,

psum(i,k+1) = psum(i,k) + psum(ik,k)

you can use the following function:您可以使用以下功能:

def partitionp(n):
    partpsum = [1] * (n + 1)
    for i in range(2, n + 1):
        for j in range(i, n + 1):
            partpsum[j] += partpsum[j - i]
    return partpsum[n]

At each iteration of the outer for loop, the list partpsum contains all the value psum(1,k), psum(2,k), psum(3,k), ..., psum(n,k).在外部 for 循环的每次迭代中,列表partpsum包含所有值 psum(1,k), psum(2,k), psum(3,k), ..., psum(n,k)。 At the end of the iteration, you only need to return psum(n,n).在迭代结束时,您只需要返回 psum(n,n)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM