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从不使事情过度复杂化。