0)返回n*事实(n-1); }; 内部不合格报告(内部n,内部r){ 如果(n==r)返回1; 如果(r==0&&n!=0)返回1; else返回(n*事实(n-1))/事实(n-1)*事实(n-r); }; int main(){ int n;//coutn; INTR; //库特; int结果=NCR(n,r); 不能使用double而不是int,c++,combinatorics,binomial-coefficients,C++,Combinatorics,Binomial Coefficients" /> 0)返回n*事实(n-1); }; 内部不合格报告(内部n,内部r){ 如果(n==r)返回1; 如果(r==0&&n!=0)返回1; else返回(n*事实(n-1))/事实(n-1)*事实(n-r); }; int main(){ int n;//coutn; INTR; //库特; int结果=NCR(n,r); 不能使用double而不是int,c++,combinatorics,binomial-coefficients,C++,Combinatorics,Binomial Coefficients" />

C+中的组合数(N选择R)+; 这里我试着用C++编写一个程序来查找NCR。但是我在结果中遇到了一个问题。这是不对的。你能帮我找出程序中的错误吗 #include <iostream> using namespace std; int fact(int n){ if(n==0) return 1; if (n>0) return n*fact(n-1); }; int NCR(int n,int r){ if(n==r) return 1; if (r==0&&n!=0) return 1; else return (n*fact(n-1))/fact(n-1)*fact(n-r); }; int main(){ int n; //cout<<"Enter A Digit for n"; cin>>n; int r; //cout<<"Enter A Digit for r"; cin>>r; int result=NCR(n,r); cout<<result; return 0; } #包括 使用名称空间std; 整数事实(整数n){ 如果(n==0)返回1; 如果(n>0)返回n*事实(n-1); }; 内部不合格报告(内部n,内部r){ 如果(n==r)返回1; 如果(r==0&&n!=0)返回1; else返回(n*事实(n-1))/事实(n-1)*事实(n-r); }; int main(){ int n;//coutn; INTR; //库特; int结果=NCR(n,r); 不能使用double而不是int

C+中的组合数(N选择R)+; 这里我试着用C++编写一个程序来查找NCR。但是我在结果中遇到了一个问题。这是不对的。你能帮我找出程序中的错误吗 #include <iostream> using namespace std; int fact(int n){ if(n==0) return 1; if (n>0) return n*fact(n-1); }; int NCR(int n,int r){ if(n==r) return 1; if (r==0&&n!=0) return 1; else return (n*fact(n-1))/fact(n-1)*fact(n-r); }; int main(){ int n; //cout<<"Enter A Digit for n"; cin>>n; int r; //cout<<"Enter A Digit for r"; cin>>r; int result=NCR(n,r); cout<<result; return 0; } #包括 使用名称空间std; 整数事实(整数n){ 如果(n==0)返回1; 如果(n>0)返回n*事实(n-1); }; 内部不合格报告(内部n,内部r){ 如果(n==r)返回1; 如果(r==0&&n!=0)返回1; else返回(n*事实(n-1))/事实(n-1)*事实(n-r); }; int main(){ int n;//coutn; INTR; //库特; int结果=NCR(n,r); 不能使用double而不是int,c++,combinatorics,binomial-coefficients,C++,Combinatorics,Binomial Coefficients,更新: 你的公式也是错误的。你应该使用fact(n)/fact(r)/fact(n-r)你的公式是完全错误的,它应该是fact(n)/fact(r)/fact(n-r),但这反过来又是一种非常低效的计算方法 请看,特别是我对这个问题的评论。(哦,请重新打开这个问题,以便我能正确回答) 单个拆分案例实际上非常容易处理: unsigned nChoosek( unsigned n, unsigned k ) { if (k > n) return 0; if (k * 2 &g

更新:


你的公式也是错误的。你应该使用
fact(n)/fact(r)/fact(n-r)

你的公式是完全错误的,它应该是
fact(n)/fact(r)/fact(n-r)
,但这反过来又是一种非常低效的计算方法

请看,特别是我对这个问题的评论。(哦,请重新打开这个问题,以便我能正确回答)

单个拆分案例实际上非常容易处理:

unsigned nChoosek( unsigned n, unsigned k )
{
    if (k > n) return 0;
    if (k * 2 > n) k = n-k;
    if (k == 0) return 1;

    int result = n;
    for( int i = 2; i <= k; ++i ) {
        result *= (n-i+1);
        result /= i;
    }
    return result;
}
unsigned nChoosek(unsigned n,unsigned k)
{
如果(k>n)返回0;
如果(k*2>n)k=n-k;
如果(k==0)返回1;
int结果=n;
对于(int i=2;i系数_表;
空隙填充筛(内部n)
{
系数表。调整大小(n+1);
对于(inti=1;i

else return (n*fact(n-1))/fact(n-1)*fact(n-r);
应该是

else return (n*fact(n-1))/(fact(r)*fact(n-r));
甚至

else return fact(n)/(fact(r)*fact(n-r));

实现n-choose-k的一个好方法是不基于阶乘,而是基于与阶乘密切相关的“升积”函数


rising_乘积(m,n)乘以m*(m+1)*(m+2)*……*n,以及处理各种极端情况的规则,如n>=m,或n这是为了在竞争性编程中解决nCr时不超过时间限制,我发布这篇文章,因为它将对你有所帮助,因为你已经得到了你问题的答案, 获得二项式系数的素因子分解可能是计算二项式系数的最有效方法,尤其是在乘法非常昂贵的情况下。计算阶乘的相关问题肯定是如此(参见示例)

这是一个基于Eratosthenes筛的简单算法,用于计算素数分解。其基本思想是在使用筛找到素数时对其进行检查,然后还计算其倍数在[1,k]和[n-k+1,n]范围内的数量。筛本质上是一个O(n\log\log n)算法,但没有进行乘法。一旦找到素因子分解,实际需要的乘法次数最多为O\left(\frac{n\log\log n}{\log n}\right),可能还有比这更快的方法

prime_factors = []

n = 20
k = 10

composite = [True] * 2 + [False] * n

for p in xrange(n + 1):
if composite[p]:
    continue

q = p
m = 1
total_prime_power = 0
prime_power = [0] * (n + 1)

while True:

    prime_power[q] = prime_power[m] + 1
    r = q

    if q <= k:
        total_prime_power -= prime_power[q]

    if q > n - k:
        total_prime_power += prime_power[q]

    m += 1
    q += p

    if q > n:
        break

    composite[q] = True

prime_factors.append([p, total_prime_power])

 print prime_factors
prime_因子=[]
n=20
k=10
复合=[True]*2+[False]*n
对于X范围内的p(n+1):
如果复合[p]:
持续
q=p
m=1
总素数功率=0
素数幂=[0]*(n+1)
尽管如此:
素数幂[q]=素数幂[m]+1
r=q
如果q n-k:
总素数功率+=素数功率[q]
m+=1
q+=p
如果q>n:
打破
复合[q]=真
素数因子。追加([p,总素数幂])
打印素数因子

N choose R的定义是计算两个乘积并将其中一个除以另一个

(N*N-1*N-2*..*N-R+1)/(1*2*3*..*R)

但是,乘法运算可能会变得太大,并且很快就会溢出现有的数据类型

(N) /1*(N-1)/2*(N-2)/3*…*(N-R+1)/R

它保证在每一步的结果都是可除的(对于n个连续数,其中一个必须被n除,这些数的乘积也是可除的)

例如,对于N选择3,N,N-1,N-2中的至少一个将是3的倍数,而对于N选择4,N,N-1,N-2,N-3中的至少一个将是4的倍数

下面给出了C++代码

int NCR(int n, int r)
{
    if (r == 0) return 1;

    /*
     Extra computation saving for large R,
     using property:
     N choose R = N choose (N-R)
    */
    if (r > n / 2) return NCR(n, n - r); 

    long res = 1; 

    for (int k = 1; k <= r; ++k)
    {
        res *= n - k + 1;
        res /= k;
    }

    return res;
}
intncr(intn,intr)
{
如果(r==0)返回1;
/*
为大R节省额外计算,
使用属性:
N选择R=N选择(N-R)
*/
如果(r>n/2)返回NCR(n,n-r);
长res=1;

对于(int k=1;k递归函数在此处使用不正确。
fact()
函数应更改为:

int fact(int n){
if(n==0||n==1) //factorial of both 0 and 1 is 1. Base case.
{
    return 1;
}else

    return (n*fact(n-1));//recursive call.
int NCR(int n,int r){
    if(n==r) {
        return 1;
    } else if (r==0&&n!=0) {
        return 1;
    } else if(r==1)
    {
        return n;
    }
    else
    {
        return fact(n)/(fact(r)*fact(n-r));
    }
};
})

递归调用应该在
else
部分中进行

NCR()
函数应更改为:

int fact(int n){
if(n==0||n==1) //factorial of both 0 and 1 is 1. Base case.
{
    return 1;
}else

    return (n*fact(n-1));//recursive call.
int NCR(int n,int r){
    if(n==r) {
        return 1;
    } else if (r==0&&n!=0) {
        return 1;
    } else if(r==1)
    {
        return n;
    }
    else
    {
        return fact(n)/(fact(r)*fact(n-r));
    }
};

你的公式是错误的,它的分子和分母都有
fact(n-1)
(它们相互抵消)。你犯了一些与OP相同的错误。
fact(n-r)
需要是除数,而不是乘法因子。是的!我不想检查公式,因为使用
int
也会产生错误的结果。即使使用
double
也不是一个很好的方法。尝试计算
6000选择3
。它很容易适用于32位
int
,但使用该公式和doubles将惨败。哎呀……我的意思是
600 choose 3
很容易适应。
6000 choose 3
实际上不适合。请注意,我3年前在回答中提供的代码不仅不使用动态列表增长,而且还使用因子分解来解决组合数问题。在语言中,question要求的(我猜这里的是python?)。是否应该
res
long
呢?仅适用于在除法发生之前res*=n-k+1步溢出的情况。提醒读者,nChoosek代码缺少n=k始终等于1的情况,请记住添加该条件。@IAmRoot看起来n=k的情况将由if(k*2>n)处理k=n-k;(k现在是0)如果(k==0)返回1;@dodecaplex:正是如此。进入循环也不会造成任何伤害,只是没有理由,正如您所指出的,早期退出优化确实涵盖了这种情况。@IAmRoot从不使事情过度复杂化。