码迷,mamicode.com
首页 > 其他好文 > 详细

solution for POJ 1001

时间:2015-12-13 00:40:18      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:

  http://poj.org/problem?id=1001

  POJ的前几道题理解起来很简单,算法也不复杂,只是需要花很长的时间去调试。1001本质上就是一个大数运算的问题,大数乘法的问题可以采用分治法,具体参考这篇文章:http://blog.csdn.net/tjsinor2008/article/details/5625849。代码如下:

 

  1 #include<stdio.h>
  2 #include<memory.h>
  3 
  4 unsigned char a[200],b[200],c[200];
  5 int lenA,lenB,maxlen,digit,p;
  /*a[200],b[200],c[200]用来存储数据,底数去掉小数点以后存储在a里面,从高位到低位每一位储存一个数字,b保存每次乘法的结果,将该结果加上小数点并去掉0前缀和后缀存在c里面,最后打印出来。最开始用的char*,而不是char[],后来发现因为最后计算的结果往往都是很长的字符串,会导致字符串b和c有一部分重合,计算结果不正确。最终改为数组以后解决了这个问题。*/
  7 int strlength(char* s)
  8 {
  9     int result=0;
 10     while(*s!=0)
 11     {
 12         result++;
 13         s++;
 14     }
 15     return result;
 16 }
 17 
/*乘法函数的关键在于对c[i+j+1]和c[i+j]修改赋值的这个循环,仔细想想不难理解。需要注意的是c[i+j]+=(c[i+j+1]-‘0‘)/10这一句可能会导致在循环结束的时候有数组的元素大于‘9’,所以最后需要再重新对计算结果从后往前遍历一遍,将该进位的进位。*/ 18 void mul(unsigned char* a,unsigned char* b) 19 { 20 int i,j; 21 lenA=strlength(a); 22 lenB=strlength(b); 23 maxlen=lenA+lenB; 24 25 for(i=0;i<maxlen;i++) 26 { 27 c[i]=0; 28 } 29 c[maxlen]=\0; 30 31 for(i=0;i<lenA;i++) 32 { 33 for(j=0;j<lenB;j++) 34 { 35 c[i+j+1]+=(a[i]-0)*(b[j]-0); 36 c[i+j]+=(c[i+j+1]-0)/10; 37 c[i+j+1]=(c[i+j+1]-0)%10+0; 38 } 39 } 40 41 for(i=maxlen-1;i>=0;i--) 42 { 43 if(c[i]>9) 44 { 45 c[i-1]+=(c[i]-0)/10; 46 c[i]=(c[i]-0)%10+0; 47 } 48 } 49 50 memcpy(b,c,maxlen+1); 51 } 52
/*把计算结果加上小数点并去除掉前置和后置的不必要的0。为避免不必要的麻烦,我先把小数点加到该加的位置上,然后再处理多余的0.需要注意的是如果最后结果是以‘.’也就是以小数/点结尾(比如底数本来就是整数),那么这个小数点也是不需要的。*/ 53 void trim() 54 { 55 int i,len,headzerocount,trailzerocount; 56 headzerocount=trailzerocount=0; 57 len=strlength(b); 58 memmove(b+len-digit+1,b+len-digit,digit+1); 59 b[len-digit]=.; 60 61 for(i=0;i<len+1;i++) 62 { 63 if(b[i]==0) 64 { 65 headzerocount++; 66 continue; 67 } 68 break; 69 } 70 for(i=len;i>=0;i--) 71 { 72 if(b[i]==0) 73 { 74 trailzerocount++; 75 continue; 76 } 77 break; 78 } 79 for(i=0;i<len-headzerocount-trailzerocount+1;i++) 80 { 81 c[i]=b[i+headzerocount]; 82 } 83 if(c[len-headzerocount-trailzerocount]==.) 84 { 85 c[len-headzerocount-trailzerocount]=0; 86 } 87 else 88 { 89 c[len-headzerocount-trailzerocount+1]=0; 90 } 91 } 92 93 int main() 94 { 95 int i; 96 97 //mul("98999","98999"); 98 99 while(scanf("%s %d",a,&p)!=EOF) 100 { 101 b[0]=1; 102 b[1]=0; 103 for(i=0;i<5;i++) 104 { 105 if(a[i]==.) 106 { 107 memmove(a+i,a+i+1,6-i); 108 digit=(6-i-1)*p; 109 break; 110 } 111 } 112 113 for(i=0;i<p;i++) 114 { 115 mul(a,b); //每次乘的结果都放在b里面 116 } 117 118 trim(); 119 printf("%s\n",c); //去掉0,加上小数点以后的值放在c里面 120 } 121 return 0; 122 }

 

 

 

总结一下,除了实现大数乘法和把小数点放到正确的位置上,还需要注意的细节有如下几点:

1.因为运算结果很有可能是比较长的字符串,所以需要注意不要让储存数据的数据结构有地址重叠的部分。

2.大数相乘时记得最后从后向前遍历一次把未进位的数位进位掉。

3.如果最终结果是个整数,那么小数点是没有用的,记得把它去掉。

solution for POJ 1001

标签:

原文地址:http://www.cnblogs.com/Nbox1989/p/5042094.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!