代码中的二项式系数调节

时间:2018-12-06 10:03:49

标签: c++

我最近以节省时间和空间的方式看到了二项式系数的代码。

ll C(ll n,ll k)
{
    ll p=1;

    if(k>n-k)
    k=n-k;

    for(int i=0;i<k;i++)
    {
    p*=(n-i);
    p/=(i+1);
    }

return p;
}

让我们考虑以下三种不同的方法。

情况1:

for(int i=0;i<k;i++)
{
p*=(n-i);
p/=(i+1);
}

情况2:

for(int i=0;i<k;i++)
{
p*=(n-i)/(i+1);
}

情况3:

for(int i=0;i<k;i++)
p*=(n-i);

for(int i=0;i<k;i++)
p/=(n-i);

在情况1和情况3中答案都是正确的,在情况2中,答案是不同的。 但是只有情况3才能给出正确的答案,而在这两种情况下,分数和分数都不会在乘法之后由于除法而被删除。

有人可以向我解释这个东西吗?

2 个答案:

答案 0 :(得分:2)

考虑案例1:

for(int i=0;i<k;i++)
{
  p*=(n-i); //statement 1
  p/=(i+1); //statement 2
}

在第一次迭代中,它将是整数除法,因为i为1。 在第二次迭代中,在语句1中,p将是奇数和偶数(因为它们是连续的)的乘积,因此将在语句2中被2整除。

在第三次迭代中,在语句1中,p将是三个连续数字按降序排列的乘积,因此将在语句2中被3整除。

依此类推...

考虑案例2:
失败是因为整数除法首先在语句的rhs中执行

p*=(n-i)/(i+1);

这会导致截断,并且您已经正确地推测了这一点。

考虑案例3: 我相信您的代码应为:

for(int i=0;i<k;i++)
p*=(n-i);

for(int i=0;i<k;i++)
p/=(i+1);

在这里,我们看到的情况与情况1相似,但这很明显。 您先以降序(最多k)然后之后的顺序将连续整数相乘 将其除以整数乘积(最多k)。这是二项式系数的公式,可以给出正确的结果。

注意:由于案例3 在除法开始之前具有连续的乘法,所以可能会出现溢出。因此,案例1 是首选。

答案 1 :(得分:1)

在处理整数算术时,评估顺序很重要。

稍微改一下您的案子,

1:先乘

p = (p * (n-i)) / (i+1)

和2:首先划分

p = p * ((n-i) / (i+1))

如果n-i小于i+1,则(n-i)/(i+1)为零。
因此,您的情况2将得出零,而情况1则不会。

例如,如果您有

 int x = 2;

然后x *= 3/4;导致x为0,但在x *= 3; x /= 4;之后为1。

您的情况3必须是错字,但也是“先乘”的情况。