1001 test
- 时间限制:
- 500ms
- 内存限制:
- 65536kB
- 描述
-
Problems involving the computation of exact values of very large magnitude and precision are common. For example, the computation of the national debt is a taxing experience for many computer systems.
This problem requires that you write a program to compute the exact value of Rn where R is a real number ( 0.0 < R < 99.999 ) and n is an integer such that 0 < n <= 25.
- 输入
- The input will consist of a set of pairs of values for R and n. The R value will occupy columns 1 through 6, and the n value will be in columns 8 and 9.
- 输出
- The output will consist of one line for each line of input giving the exact value of R^n. Leading zeros should be suppressed in the output. Insignificant trailing zeros must not be printed. Don't print the decimal point if the result is an integer.
- 样例输入
-
95.123 12 0.4321 20 5.1234 15 6.7592 9 98.999 10 1.0100 12
- 样例输出
-
548815620517731830194541.899025343415715973535967221869852721 .00000005148554641076956121994511276767154838481760200726351203835429763013462401 43992025569.928573701266488041146654993318703707511666295476720493953024 29448126.764121021618164430206909037173276672 90429072743629540498.107596019456651774561044010001 1.126825030131969720661201
这是POJ正式题目的第1题,其实这道题目难度还是颇大的。尤其是紧跟在A+B这道熟悉POJ性质的题目后面,颇有点儿下马威的意思。分析这道题目:中文翻译过来也就是求任意浮点数的n次方精确值的问题,如样例给出的 95.123 的12 次方是
548815620517731830194541.899025343415715973535967221869852721
解题思路如下:
(1)绝对不能使用浮点数直接运算,因为就算是double类型,也不可能保存完整精确结果
(2)采用字符模拟CPU硬件乘法是基本解题思路
(3)采用ASCII码进行运算,如 ('6' -'0')*('5'-'0') = 30,30可以分解为 进位'3' 和 结果'0'
有了这样的解题思路那么我先给出一个解(由于初次尝试POJ的时候没有经验,这道题的这个解是查阅网络得来的,但已经验证通过):
#include<stdio.h> #include<stdlib.h> #include<string.h> #define Len 200 char r[2*Len-1]; //大整数乘法:输入两个数字串,返回一个结果串(去除前导0的) void lnmp(char *cs,char *bcs) { char cjr[Len][Len][2]; int i,j,k,l,cslen,bcslen,rlen,jw=0,temp,out=0; cslen=strlen(cs); bcslen=strlen(bcs); rlen=cslen+bcslen-1; //生成矩形表(三维数组) for(i=cslen-1;i>=0;i--) for(j=bcslen-1;j>=0;j--) { temp=(cs[i]-'0')*(bcs[j]-'0'); cjr[j][i][0]=temp/10; cjr[j][i][1]=temp%10; } //求出结果(注意一个规律性的东西,从最后一位到最前一位,为矩形表里头的下标递减的数字之和) for(l=rlen;l>=0;l--) { temp=jw; for(i=cslen-1;i>=0;i--) for(j=bcslen-1;j>=0;j--) for(k=1;k>=0;k--) if(l==i+j+k) temp=temp+cjr[j][i][k]; jw=temp/10; r[l]=temp%10+'0'; } for(l=0;l<rlen;l++) if(r[l]!='0') break; if(l) for(i=l;i<=rlen+1;i++) r[i-l]=r[i]; } int main() { char R[Len]; int N; int i,j,k,xsdws,temp,flag; while(scanf("%s %d",R,&N)!=EOF) { i=1,flag=0; temp=strlen(r); for(i=0;i<temp;i++) r[i]='\0'; //求小数点的位置 temp=strlen(R); for(i=0;i<temp;i++) if(R[i]=='.') break; //如果是小数,先转换成整数,后面再转换回来 if(i!=temp) { flag=1; xsdws=(temp-i-1)*N; for(j=i;j<=temp;j++) R[j]=R[j+1]; } //去除前导零,减少不必要的计算次数 for(i=0;i<temp;i++) if(R[i]!='0') break; if(i) for(j=i;j<=temp;j++) R[j-i]=R[j]; strcpy(r,R); for(i=1;i<N;i++) lnmp(r,R); temp=strlen(r); //如果是整数,直接输出结果,否则要考虑几种情况 if(!flag) { for(j=0;j<temp;j++) putchar(r[j]); } //为小数时,需要考虑去掉末尾无效的零,如果位数不够,需要补充零,下面将出示比较典型的例子 else { i=temp-xsdws; if(temp>xsdws) { i=temp-xsdws; for(j=0;j<i;j++) putchar(r[j]); for(k=temp-1;k>=0;k--) if(r[k]!='0') break; if(i<=k) putchar('.'); for(j=i;j<k+1;j++) putchar(r[j]); } else { i=xsdws-temp; putchar('.'); for(j=0;j<i;j++) putchar('0'); for(k=temp-1;k>=0;k--) if(r[k]!='0') break; for(j=0;j<k+1;j++) putchar(r[j]); } } putchar('\n'); } return 0; }
我后来自己做了一次
//============================================================================ // Name : POJ-1001.cpp //======================================== #include <iostream> #include <algorithm> using namespace std; std::string multiply(const std::string& a, const std::string& b) { int a_len = a.length(); int b_len = b.length(); /*最终结果*/ std::string result; /*设置初始结果,"0000...000",与b的位数相同*/ result.assign(b_len,'0'); /*临时结果、临时进位*/ int consq = 0; int carry = 0; for(int i=a_len-1; i>=0; --i) { for(int j=b_len-1; j>=0; --j) { consq = (a.at(i)-'0') * ( b.at(j)-'0') + (result.at(a_len-i+b_len-j-2)-'0') + carry ; carry = 0; if( consq >9 ) { int temp = consq/10; carry = temp; consq = consq - carry*10; } result.at(a_len-i+b_len-j-2) = (consq+'0'); } result.push_back(carry+'0'); carry = 0; } /*处理最终结果*/ if( result.at(a_len+b_len-1) == '0') { result.erase(result.length()-1,1); } /*翻转得到最终结果*/ for(int i=0; i<result.length()/2; ++i) { char tmp = result.at(i); result.at(i) = result.at(result.length()-1-i); result.at(result.length()-1-i) = tmp; } return result; }; int main() { string R; int n; while(cin>>R>>n) { string result = "1"; int pos = R.find("."); if( pos < 0)/*R是整数*/ { while( --n >= 0 ) result = multiply(R,result); } else /*R是小数*/ { R.erase(pos,1); int dot_num = R.length()-pos; int res_dot = dot_num * n; while( --n >= 0 ) result = multiply(R,result); int dot_pos = result.length()-res_dot; while( dot_pos <= 0 ) { result.insert(dot_pos,"0"); dot_pos++; } result.insert(dot_pos,"."); /*去掉后缀不必要的0*/ while( result.at(result.length()-1) =='0') result.erase(result.length()-1,1); } /*去掉不必要的0*/ while( result.at(0) =='0') result.erase(0,1); cout<<result.c_str()<<endl; } return 0; }
但不知道为什么总时wrong answer,我检查过和Accept的解法的输出,应该是一致的,但就是通不过,汗……做个POJ的同学指教一下吧,求高手!!!