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

原帖链接: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的大小进行调整),利用组与组的错位相乘再相加,可以避免楼主这样逐位进行运算。

代码如下:

#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 ;
}
BigInteger BigInteger::
operator + ( const  BigInteger  &  n)  const  
{
    BigInteger a 
=   * this ;
    a.add(n);
    
return  a;
}
BigInteger BigInteger::
operator - ( const  BigInteger  &  T)  const
{
    BigInteger b 
=   * this ;
    b.sub(T);
    
return  b;
}
BigInteger BigInteger::
operator   *  ( const  BigInteger  & rhs)  const
{
    BigInteger result;
    
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;
}
BigInteger BigInteger::
operator / ( const   int   &  b)  const
{
    BigInteger ret;
    
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_t   start,   finish;   
    
double      duration;   
    
int  i,n;
    BigInteger result,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(   
" %f   seconds/n " ,   duration   );   
    
return   0 ;
}

下面给出测试结果,

我的机器配置:酷睿双核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!的非零末尾数,有兴趣的同学可以自己看看。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值