【问题标题】:combinations of N same balls in A different boxesN个相同球在不同盒子中的组合
【发布时间】:2019-04-24 22:30:38
【问题描述】:
int f(int n,int a,int x)
{
        if(a==1)
        {
            if(n>=0 && n<=x)  //HERE WAS ERROR,sorry
                return 1;
            else 
                return 0;
        }

        int ans=0;

        for(int i=0;i<=x;i++)
            ans += f(n-i,a-1,x);

    return ans;
}

你好!

例子:

这是算法,但它花费了很多时间。 也许您知道解决此问题的更快方法?非常感谢,很抱歉让您担心。

【问题讨论】:

  • 语言?可能是 C99、C++、C#、Java,还有什么?
  • @leppie: 由于 OP 称其为算法,它必须是伪代码;)
  • @leppie 我认为这并不重要——重要的是算法。
  • @LuVue:如果您的示例的答案是 1,那么为什么您的函数返回 9?哦,答案是动态规划。
  • @leppie:没关系,我就是想知道算法……

标签: algorithm combinatorics


【解决方案1】:

您需要的是动态编程。您需要记住已经计算过的那些参数的函数 f 的值。它也可以在没有递归的情况下实现,如下所示:

int f(int n,int a,int x)
{
    int q[1000][50]; // to simplify and not use dynamic allocation assume that a < 50 and n < 1000

    q[0][0] = 1;
    for (int i = 1; i < 1000; ++i)
        q[i][0] = 0;

    for (int i = 1; i <= a; ++i)
    {
        for (int j = 0; j <= n; j++)
        {
            int t = 0;
            for (int l = 0; l <= j && l <= x; ++l)
                t += q[j - l][i-1];
            q[j][i] = t;
        }
    }

    return q[n][a];
}

这只是简单的技术演示。它可以再优化一次,您可以预先计算 t-sum 并消除 l 的循环。而且你不必存储整个表q,你只需要两层,它会减少内存使用。所以结果会是这样的:

int f(int n,int a,int x)
{
    int q[1000][2]; // to simplify and not use dynamic allocation assume n < 1000

    q[0][0] = 1;
    for (int i = 1; i < 1000; ++i)
        q[i][0] = 0;

    int current = 1;
    for (int i = 1; i <= a; ++i)
    {
        int t = 0;
        for (int j = 0; j <= n; j++)
        {
            t += q[j][1 - current];
            if (j > x)
                t -= q[j - x - 1][1 - current];

            q[j][current] = t;
        }
        current = 1 - current;
    }

    return q[n][1 - current];
}

所以最终计算需要 O(a*n) 时间。

PS:请注意,答案可能是一个巨大的数字,可能会溢出任何本机整数类型。

【讨论】:

  • 你不需要比 [X+1] 更大的记忆数组
  • 同意。但这会使代码更复杂一些。我猜 2*n 变体足以解释技术。如果您可以添加具有 x+1 记忆的可理解示例,欢迎您。
【解决方案2】:

首先,如果A*X &lt; N,没有办法分配球,所以你可以早点停下来。如果A*X == N,只有一种方法。然后,首先选择放置X 球的盒子数量并以较小的限制重复出现可能会更快。

int f(int n, int a, int x){   // should all be unsigned, actually
    if (n == 0){
        return 1;
    }
    int p = a*x;
    if (p < n){
        return 0;
    }
    if (p == n){
        return 1;
    }
    if (x == 1){
        return binom(a,n);    // ways to choose n boxes from a boxes
    }
    // now the interesting cases
    int ways = 0;    // should perhaps be unsigned long long, that number grows fast
    int xCount, tempRes, min, max;
    min = a+n-p;
    if (min < 0) min = 0;
    max = n/x;
    for(xCount = min; xCount <= max; ++xCount){
        tempRes = f(n - x*xCount,a - xCount, x-1); // ways to distribute the remaining balls
        ways += binom(a,xCount)*tempRes;    // multiply by the number of ways to choose xCount boxes
    }
    return ways;
}

如果您经常致电f,则为二项式系数创建一个表格可能会很有用。

【讨论】:

    【解决方案3】:

    查看http://www.mathpages.com/home/kmath337.htm 和页面底部的公式。

    【讨论】:

    • 你的意思是 C[m+k-s(t,j)-1,m-1] ?
    • 在底部,您可以找到 N(k) 的公式,它是 m 项的交替总和,其中 m 应该是框的数量(每个项是某些二项式系数的乘积)。
    • 约翰唐,我不明白这个:(
    • @LuVue 底部只有一个公式。它是纯文本的,因此可能难以阅读。 This 可能会有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多