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

原帖链接: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>
usingnamespacestd;
#include
"time.h"

constintMAX_GROUPS=20000;//最多2万组,每组最多4位整数,即最多可容纳8万位整数
constintMAXN=9999;//每组的上限值
constintGROUP_LEN=4;//每组的最大长度

classBigInteger
{
private:
intdata[MAX_GROUPS];
intlen;
voidinit()
{
memset(data,
0,sizeof(data));
}
public:
BigInteger()
{
init();
len
=0;
}
BigInteger(
constintb);
BigInteger(
constBigInteger&);

booloperator>(constBigInteger&)const;
BigInteger
&operator=(constBigInteger&);
BigInteger
&add(constBigInteger&);
BigInteger
&sub(constBigInteger&);
BigInteger
operator+(constBigInteger&)const;
BigInteger
operator-(constBigInteger&)const;
BigInteger
operator*(constBigInteger&)const;
BigInteger
operator/(constint&)const;
voidprint();
};
BigInteger::BigInteger(
constintnum)
{
intres,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(
constBigInteger&rhs):len(rhs.len)
{
inti;
init();
for(i=0;i<len;i++)
{
data[i]
=rhs.data[i];
}
}
boolBigInteger::operator>(constBigInteger&rhs)const
{
intln;
if(len>rhs.len)
{
returntrue;
}
elseif(len<rhs.len)
{
returnfalse;
}
elseif(len==rhs.len)
{
ln
=len-1;
while(data[ln]==rhs.data[ln]&&ln>=0)
{
ln
--;
}
if(ln>=0&&data[ln]>rhs.data[ln])
{
returntrue;
}
else
{
returnfalse;
}
}

}

BigInteger
&BigInteger::operator=(constBigInteger&rhs)
{
init();
len
=rhs.len;
for(inti=0;i<len;i++)
{
data[i]
=rhs.data[i];
}
return*this;
}
BigInteger
&BigInteger::add(constBigInteger&rhs)
{
inti,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(constBigInteger&rhs)
{
inti,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;
}
}
elseif(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+(constBigInteger&n)const
{
BigIntegera
=*this;
a.add(n);
returna;
}
BigIntegerBigInteger::
operator-(constBigInteger&T)const
{
BigIntegerb
=*this;
b.sub(T);
returnb;
}
BigIntegerBigInteger::
operator*(constBigInteger&rhs)const
{
BigIntegerresult;
inti,j,up;
inttemp,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--;
returnresult;
}
BigIntegerBigInteger::
operator/(constint&b)const
{
BigIntegerret;
inti,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--;
returnret;
}
voidBigInteger::print()
{
inti;

cout
<<data[len-1];
for(i=len-2;i>=0;i--)
{
cout.width(GROUP_LEN);
cout.fill(
'0');
cout
<<data[i];
}
cout
<<endl;
}
intmain()
{
clock_tstart,finish;
doubleduration;
inti,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);
return0;
}

下面给出测试结果,

<!--<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!的非零末尾数,有兴趣的同学可以自己看看。

阅读更多
换一批

没有更多推荐了,返回首页