Chinaunix首页 | 论坛 | 博客
  • 博客访问: 452810
  • 博文数量: 98
  • 博客积分: 6011
  • 博客等级: 准将
  • 技术积分: 1030
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-23 13:19
文章分类

全部博文(98)

文章存档

2011年(2)

2009年(2)

2008年(31)

2007年(35)

2006年(28)

我的朋友

分类: 项目管理

2007-11-05 23:11:56

求N!,由 N!=N*(N-1)!,所以求解N!的算法就是递推法。
当N值很小时可以直接用int型数据进行运算就可以解决了,但当N值很大,比如N=10000或跟大时就没有办法用具体的数据类型来存放这样大的,因为他们的为数都远远超过了int ,long甚至long long型的范围(如10000!有35660位)。
为了解决所有数据类型都无法存放这样一个庞大的数据,我向到了可以将这样一个数据一位一位的存放到一个字符数组或int型数组中,对其每一位进行单独运算,然后将结果存放到另一个数组里,这样就解决了庞大数据的存放问题。但具体怎样对两个都比较大的数的作乘法运算呢?这就要利用大整数的高精度运算。A,B都是位数比较多的大整数,现在要作A*B运算。小学时我们作45*12是先把12中的2与45的个位5相乘,再把2与45的十位4相乘,然后同样再把12中的1与45中的每一位从低到高依次相乘。在这里我们模拟也可以45*12,把A中每一位从低到高与B中的个位相乘,与后再与B中的十位相乘,依次类推,最后把所有的结果对应相加就可以得到所要求的结果了。
我们用a[100000]来存N!的结果,如十进制数3478,存在a里面是:a[0]=4(记录数的长度),a[1]=8,a[2]=7,
a[3]=4,a[4]=3;
//实现代码如下:
#include
using namespace std;
int a[40000];
int main()
{
 int N,i,j,pre;
 
 while(cin>>N)
 {
  a[0]=1;a[1]=1;
  if(N==0||N==1)
  {
   cout<<1<   continue;
  }
  for(i=2;i<=N;i++)
  {
   pre=0;
   for(j=1;j<=a[0];j++)
   {
    a[j]*=i;
    a[j]+=pre;//加上进位
    pre=a[j]/10;//进位值
    a[j]%=10;//本位
   }
   while(pre)//对末尾的进位进行存储
   {
    a[j]=pre%10;
    a[0]=j;
    pre/=10;
    j++;
   }
  }
  for(i=a[0];i>=1;i--)//输出
   cout<  cout< }
 return 0;
}
//hdu 1042 通过,耗时1850MS
//但是上面算法的效率不高,10000!的阶乘要将近2S才能算出来,不能解决实际问题.为了达到更好的效果,必须进行优化.在杭电的论坛上看到有人用类似的方法,但进行了改进,原理是大小不同的数的加法运算时间是基本相等的(<算法艺术与信息学竞赛> 黄亮,刘汝佳著).上面的程序是由于每一位每一位相加求得,但数非常大时,位数会很多,每进行一次乘都要进行几万位的运行,累计起来,这是一个非常大的时间开销.我们何不在数位的每个元素中存放在5-10位,而不是1位.(int型最多5位,因为两个5位数相乘不会超出整型范围,6位就超了,也可采用能表达的更大的数据类型,那样时间更省.)
//代码如下:
#include
using namespace std;
#define M 10000000000
unsigned __int64 a[20000];
int main()
{
 int N,i,j;
 unsigned __int64 pre;
 while(cin>>N)
 {
  a[0]=1;a[1]=1;
  if(N==0||N==1)
  {
   cout<<1<   continue;
  }
  for(i=2;i<=N;i++)
  {
   pre=0;
   for(j=1;j<=a[0];j++)
   {
    a[j]*=i;
    a[j]+=pre;
    pre=a[j]/M;
    a[j]%=M;
   }
   while(pre)
   {
    a[j]=pre%M;
    a[0]=j;
    pre/=M;
    j++;
   }
  }
  printf("%I64u",a[a[0]]);
  for(i=a[0]-1;i>0;i--)
  {
   if(a[i]<10) cout<<"000000000";
   else if(a[i]<100) cout<<"00000000";
   else if(a[i]<1000) cout<<"0000000";
   else if(a[i]<10000) cout<<"000000";
   else if(a[i]<100000) cout<<"00000";
   else if(a[i]<1000000) cout<<"0000";
   else if(a[i]<10000000) cout<<"000";
   else if(a[i]<100000000) cout<<"00";
   else if(a[i]<1000000000) cout<<"0";
   printf("%I64u",a[i]);
  }
  cout< }
 return 0;
}
//hdu 1042用C++提交通过 耗时1430MS,比开始那个节省了几百MS..(用G++提交不能通过,因为G++不支持64位整).
如果哪位高手有更好的方式请多多交流...
 
阅读(4030) | 评论(5) | 转发(0) |
0

上一篇:新的征程...

下一篇:无题

给主人留下些什么吧!~~

chinaunix网友2010-08-03 10:33:49

#include int main() { int a[10000]; int i,j,c,m,n; while(scanf("%d",&n)!=EOF) { a[0]=1; m=0; for(i=1;i<=n;i++) { c=0; for(j=0;j<=m;j++) {

chinaunix网友2008-10-17 21:08:22

输出到不用那么麻烦哦 printf("%04d", n); 0是说明填充为0 4是数字的宽度是4 这样就不用那么麻烦了 呵呵

chinaunix网友2008-10-15 21:39:29

thx

ewclinqin2008-09-02 11:33:08

能解释一下吗?