回《笔试常见的“阶乘”编程题,你写对了么?》

本文介绍了一种使用C++实现的大数阶乘快速计算方法,通过对数据进行分组并利用组间的错位相乘与相加,显著提高了计算效率。在测试中,10000的阶乘能在3.312秒内完成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原帖链接:http://www.cnblogs.com/kym/archive/2009/10/05/1578224.html
我机器上没有C#的开发环境,所以没法测试作者这个代码的耗时,不过10000的阶乘在5秒内完成,不知道作者的代码是否能达到?我想起前段时间在HDU做的一道ACM题,题目的时限要求是1秒内能计算10000的阶乘(当然这是代码跑在它的服务器的时间)。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1042

如果按照飞林沙文章中那种常规的思路,逐位相乘,再对齐相加,缺点很明显,如果n值比较大,运算次数将非常多,必定会超时,1万的阶乘想在1秒内完成肯定无法达成。
我的思路是把数据分组,每组上限为9999,最多可容纳2万组,每组4位整数,则可以容纳8万位整数(当然,组数可以随你要计算的n的大小进行调整),利用组与组的错位相乘再相加,可以避免楼主这样逐位进行运算。

代码如下:

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> #include < iostream >
#include
< stdio.h >
#include
< string >
#include
< iomanip >
#include
< algorithm >
using namespace std;
#include
" time.h "

const int MAX_GROUPS = 20000 ; // 最多2万组,每组最多4位整数,即最多可容纳8万位整数
const int MAXN = 9999 ; // 每组的上限值
const int GROUP_LEN = 4 ; // 每组的最大长度

class BigInteger
{
private :
int data[MAX_GROUPS];
int len;
void init()
{
memset(data,
0 , sizeof (data));
}
public :
BigInteger()
{
init();
len
= 0 ;
}
BigInteger(
const int b);
BigInteger(
const BigInteger & );

bool operator > ( const BigInteger & ) const ;
BigInteger
& operator = ( const BigInteger & );
BigInteger
& add( const BigInteger & );
BigInteger
& sub( const BigInteger & );
BigInteger
operator + ( const BigInteger & ) const ;
BigInteger
operator - ( const BigInteger & ) const ;
BigInteger
operator * ( const BigInteger & ) const ;
BigInteger
operator / ( const int & ) const ;
void print();
};
BigInteger::BigInteger(
const int num)
{
int res,tmp = num;
len
= 0 ;
init();
while (tmp > MAXN)
{
res
= tmp - tmp / (MAXN + 1 ) * (MAXN + 1 );
tmp
= tmp / (MAXN + 1 );
data[len
++ ] = res;
}
data[len
++ ] = tmp;
}
BigInteger::BigInteger(
const BigInteger & rhs):len(rhs.len)
{
int i;
init();
for (i = 0 ;i < len;i ++ )
{
data[i]
= rhs.data[i];
}
}
bool BigInteger:: operator > ( const BigInteger & rhs) const
{
int ln;
if (len > rhs.len)
{
return true ;
}
else if (len < rhs.len)
{
return false ;
}
else if (len == rhs.len)
{
ln
= len - 1 ;
while (data[ln] == rhs.data[ln] && ln >= 0 )
{
ln
-- ;
}
if (ln >= 0 && data[ln] > rhs.data[ln])
{
return true ;
}
else
{
return false ;
}
}

}

BigInteger
& BigInteger:: operator = ( const BigInteger & rhs)
{
init();
len
= rhs.len;
for ( int i = 0 ;i < len;i ++ )
{
data[i]
= rhs.data[i];
}
return * this ;
}
BigInteger
& BigInteger::add( const BigInteger & rhs)
{
int i,nLen;

nLen
= rhs.len > len ? rhs.len:len;
for (i = 0 ;i < nLen;i ++ )
{
data[i]
= data[i] + rhs.data[i];
if (data[i] > MAXN)
{
data[i
+ 1 ] ++ ;
data[i]
= data[i] - MAXN - 1 ;
}
}
if (data[nLen] != 0 )
{
len
= nLen + 1 ;
}
else
{
len
= nLen;
}

return * this ;
}
BigInteger
& BigInteger::sub( const BigInteger & rhs)
{
int i,j,nLen;
if (len > rhs.len)
{
for (i = 0 ;i < nLen;i ++ )
{
if (data[i] < rhs.data[i])
{
j
= i + 1 ;
while (data[j] == 0 )j ++ ;
data[j]
-- ;
-- j;
while (j > i)
{
data[j]
+= MAXN;
-- j;
}
data[i]
= data[i] + MAXN + 1 - rhs.data[i];
}
else
{
data[i]
-= rhs.data[i];
}
}
len
= nLen;
while (data[len - 1 ] == 0 && len > 1 )
{
-- len;
}
}
else if (len == rhs.len)
{
for (i = 0 ;i < len;i ++ )
{
data[i]
-= rhs.data[i];
}
while (data[len - 1 ] == 0 && len > 1 )
{
-- len;
}
}
return * this ;
}
BigIntegerBigInteger::
operator + ( const BigInteger & n) const
{
BigIntegera
= * this ;
a.add(n);
return a;
}
BigIntegerBigInteger::
operator - ( const BigInteger & T) const
{
BigIntegerb
= * this ;
b.sub(T);
return b;
}
BigIntegerBigInteger::
operator * ( const BigInteger & rhs) const
{
BigIntegerresult;
int i,j,up;
int temp,temp1;

for (i = 0 ;i < len;i ++ )
{
up
= 0 ;
for (j = 0 ;j < rhs.len;j ++ )
{
temp
= data[i] * rhs.data[j] + result.data[i + j] + up;
if (temp > MAXN)
{
temp1
= temp - temp / (MAXN + 1 ) * (MAXN + 1 );
up
= temp / (MAXN + 1 );
result.data[i
+ j] = temp1;
}
else
{
up
= 0 ;
result.data[i
+ j] = temp;
}
}
if (up != 0 )
{
result.data[i
+ j] = up;
}
}
result.len
= i + j;
while (result.data[result.len - 1 ] == 0 && result.len > 1 )result.len -- ;
return result;
}
BigIntegerBigInteger::
operator / ( const int & b) const
{
BigIntegerret;
int i,down = 0 ;

for (i = len - 1 ;i >= 0 ;i -- )
{
ret.data[i]
= (data[i] + down * (MAXN + 1 )) / b;
down
= data[i] + down * (MAXN + 1 ) - ret.data[i] * b;
}
ret.len
= len;
while (ret.data[ret.len - 1 ] == 0 )ret.len -- ;
return ret;
}
void BigInteger::print()
{
int i;

cout
<< data[len - 1 ];
for (i = len - 2 ;i >= 0 ;i -- )
{
cout.width(GROUP_LEN);
cout.fill(
' 0 ' );
cout
<< data[i];
}
cout
<< endl;
}
int main()
{
clock_tstart,finish;
double duration;
int i,n;
BigIntegerresult,num;
scanf(
" %d " , & n);
start
= clock();
result
= BigInteger( 1 );
for (i = 2 ;i <= n; ++ i)
{
num
= BigInteger(i);
result
= result * num;
}
result.print();
finish
= clock();
duration
= ( double )(finish - start) / CLOCKS_PER_SEC;
printf(
" %fseconds/n " ,duration);
return 0 ;
}

下面给出测试结果,

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> 我的机器配置:酷睿双核2 . 0G , 内存3G ,
计算10000的阶乘,我的机器用时3
. 312秒,在HDU的服务器上,10000的阶乘用时不到900毫秒。
计算12345的阶乘,我的机器用时5.078秒。
计算20000的阶乘,我的机器用时13.656秒。

用C/C++确实是会快些的,HDU的这道题目对Java程序的时限是5秒内完成1万的阶乘,但c/c++的时限是1秒,由此可以看出。

大家也可以试试在HDU的服务器上提交下你的代码,看看能否在1秒内通过。

此外,还有2个常见的N!题目,就是N!的尾数0的个数和N!的非零末尾数,有兴趣的同学可以自己看看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值