北大ACM1001题Exponentiation(求高精度幂)

从昨天开始训练ACM题目,每题尽量用C++和java编写,为了熟悉算法和java语言。

 题目是这样的:

求高精度幂 Time Limit: 500MS Memory Limit: 10000K Total Submissions: 44697 Accepted: 10245

Description

对数值很大、精度很高的数进行高精度计算是一类十分常见的问题。比如,对国债进行计算就是属于这类问题。

现在要你解决的问题是:对一个实数R( 0.0 < R < 99.999 ),要求写程序精确计算 R 的 n 次方(Rn),其中n 是整数并且 0 < n <= 25。 Input

T输入包括多组 R 和 n。 R 的值占第 1 到第 6 列,n 的值占第 8 和第 9 列。 Output

对于每组输入,要求输出一行,该行包含精确的 R 的 n 次方。输出需要去掉前导的 0 后不要的 0 。如果输出是整数,不要输出小数点。 Sample Input

95.123 12 0.4321 20 5.1234 15 6.7592 9 98.999 10 1.0100 12

Sample Output

548815620517731830194541.899025343415715973535967221869852721

.00000005148554641076956121994511276767154838481760200726351203835429763013462401

43992025569.928573701266488041146654993318703707511666295476720493953024

29448126.764121021618164430206909037173276672

90429072743629540498.107596019456651774561044010001

1.126825030131969720661201

下面的代码是我自己编写的,由于网络原因,一直测试为waiting,先放着,哪天测试。

C++:

思路是这样的:由于C++里面没有像java里面的BigDecimal这样的类型,只能靠算法来实现,由于数据太大,那就用数组来装载数据,数组里面的每一个元素都不会超过9,这样首先申请一个空间为250的一维数组m[250]。然后里面只存放每次相乘得到的结果。用一个6元素大小的字符数组装底数,char r[6],r[0]=9,r[1]=5,r[2]=.,r[3]=1,r[4]=2,r[5]=3,现在就不要小数点,存放在int b[6](要进行处理),对于多出来的位置,则用-1表示,这样在存放在m中就可以容易识别。然后在m中,每一位(如9)分别乘以96123,得到一个大数,这个大数就采用模10和除以10分别放在9前面的位置里面。例如9*95123=856107,然后m中对应9的位置就放7,7前面的五位数就分别加0,1,6,5,8.如果想加超过9,则还要将进的1加到前面一位。最后就是:m[4]=7,m[5]=0,m[6]=1,m[7]=6,m[8]=5等等,这样每一位都乘了95123,并且也分别存在在m中,下一个循环就是对m中的每一位数据(存放在一个数组中的一个单元里)再乘以95123,重复上面的过程n次,最后m中的数据就是结果,打印的时候也要注意有没有小数点。不知道说清楚没,就这样吧。希望下次我来看的时候能记起来。

代码:

  1 #include <iostream>
2 using namespace std;
3 int main()
4 {
5 char r[6]={'0'};//底数
6 int n=1;//指数
7 while(cin>>r>>n)
8 {
9 int m[250]={0};
10 int b[6]={0};
11 int i,j,m_i;
12 int m_number=0,m_data=0;//小数点个数,每次相乘的数据
13 for(i=0;i<6;i++)//找到小数点的位置
14 {
15 if(r[i]=='.')
16 {
17 m_i=i;
18 break;
19 }
20 }
21 if(i==6)//说明没有小数点
22 {
23 j=0;
24 while(r[j]=='0')
25 {
26 r[j]='a';
27 j++;
28 }
29 m_number=0;
30 }
31 else//说明有小数点
32 {
33 i=0;
34 while(i<m_i&&r[i]=='0')//小数点之前前导0处理为-1
35 {
36 r[i]='a';
37 i++;
38 }
39 i=5;
40 while(i>m_i&&(!r[i]||r[i]=='0'))//小数点之后的后缀零处理
41 {
42 r[i]='a';//赋值为a
43 i--;
44 }
45 for(i=5;i>=0;--i)
46 {
47 if(!r[i]||r[i]=='a')continue;
48 if(r[i]=='.')break;
49 m_number++;//判断有多少小数
50 }
51 }
52 for(i=0,j=0;i<6;++i)
53 {
54 if(r[i]=='a')continue;
55 if(r[i]=='.')continue;
56 if(!r[i])continue;
57 b[j]=(int)(r[i]-'0');//转成int的b
58 j++;
59 }
60 while(j<6)
61 {
62 b[j]=-1;
63 j++;
64 }//b可以弄出实数来了
65 for(i=0;i<6;++i)
66 {
67 if(b[i]==-1)continue;
68 m_data=m_data*10+b[i];//相乘的大数
69 }
70 for(j=5,i=250-1;j>=0&&i>=0;--j)
71 {
72 if(b[j]==-1)continue;
73 else
74 {
75 m[i]=b[j];//赋值给m
76 i--;
77 }
78 }
79 m_number=m_number*n;
80 n--;
81 while(n--&&i!=249)//如果出现输入都是0
82 {
83 for(j=i+1;j<250;j++)//有这么多位
84 {
85 int tem=m[j]*m_data;//每一位与数相乘
86 m[j]=0;
87 if(tem==0)m[j]=0;
88 else
89 {
90 int t=j;
91 while(tem/10!=0||tem%10!=0)
92 {
93 m[t]=m[t]+tem%10;//将每一位都分离出来存放在不同的单元
94 int tt1=t;
95 while(m[tt1]>9)//对超过9的处理
96 {
97 int tem2=m[tt1];
98 m[tt1]=tem2%10;//得到这位的数据
99 tt1--;
100 m[tt1]=m[tt1]+tem2/10;//往前加进的位数
101 }
102 t--;
103 tem=tem/10;
104 }
105 }
106 }
107 i=0;
108 while(m[i]==0)i++;//找到m中第一个非零的位置
109 i--;
110 }
111 i=0;
112 while(i<250&&m[i]==0)
113 i++;
114 if(m_number==0)//对没有小数点的处理
115 {
116 if(i==250)cout<<0<<endl;
117 else
118 {
119 for(;i<250;++i)cout<<m[i];
120 cout<<endl;
121 }
122 }
123 else//有小数点的处理
124 {
125 if(m_number>250-i)//250-i表示在i之前有i个零,有250-i个非零
126 {//小数点超过相乘得到的实数,则补零
127 cout<<".";
128 while(m_number-->250-i)
129 cout<<0;
130 for(;i<250;i++)
131 cout<<m[i];
132 cout<<endl;
133 }
134 else
135 {
136 for(;i<250;++i)
137 {
138 if(m_number==250-i)cout<<".";//包含处理等于
139 cout<<m[i];
140 }
141 cout<<endl;
142 }
143 }
144 }
145 return 0;
146 }

下面是用java编写:

    

 1 import java.io.*;
2 import java.util.*;
3 import java.math.BigDecimal;
4
5 public class Main
6 {
7 public static void main(String args[])throws Exception
8 {
9 Scanner cin=new Scanner(System.in);
10 while(cin.hasNext())
11 {
12 BigDecimal r=cin.nextBigDecimal();
13 int n=cin.nextInt();
14 r=r.pow(n).stripTrailingZeros();//去掉小数点后面的零
15 String m_string=r.toPlainString();//不带指数段的字符串表示形式
16 if(m_string.charAt(0)=='0')
17 m_string=m_string.substring(1);
18 System.out.println(m_string);
19 }
20 }
21 }

OK,希望自己能坚持做ACM题目。

原文地址:https://www.cnblogs.com/leewiki/p/2283911.html