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

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

posted on 2009-10-06 11:51  Phinecos(洞庭散人)  阅读(4488)  评论(13编辑  收藏  举报

导航