原帖链接: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);
- tmptmp = 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)
- {
- temptemp1 = 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);
- resultresult = 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!的非零末尾数,有兴趣的同学可以自己看看。
转载于:https://blog.51cto.com/phinecos/368956