HDU4814——数学,模拟进制转换
本题围绕:数学公式模拟进制转换
HDU4814 Golden Radio Base
题目描述
将一个十进制的非负整数转换成E(黄金分割数)进制的数
输入
不大于10^9的非负整数,处理到文件尾
输出
转换成的E进制数(可能含有小数)
样例输入
1
2
3
6
10
样例输出
1
10.01
100.01
1010.0001
10100.0101
题目分析
对于本题,要注意的点有:首先对于一个十进制的正数,我们是可以严格转换成一个E(黄金分割数)进制的数的,而不是涉及到约等于,例如10-base的n,可以转换成n*E^0(以下用E代表黄金分割数进制),此外本题给出的两个提示公式也是解题的关键,我们可以通过这两个公式得到如下两个公式:① E^n = E^n-1 + E^n-2, ② 2*E^n = E^n+1 + E^n-2,而本题的思路就是,建立一个数组a[]用于保存我们需要输出的最终答案,a[i]存放E的i次方的系数(就像是二进制一样),由于本题的输出可能包含小数,所以我们将数组的一半用于存放小数位的系数(E的-i次方位,因为通过两个公式我们得知,即使E的幂指数是负数公式仍然成立),同时我们通过计算得知E^50已经大于10^9,所以我们只要将数组开成100,且前50位存放小数点后的系数,后50位存放小数点前的系数,a[50]初始化时等于n(将50作为E的0次方位,正好对应我们上面讲到的10-base的n可以转换成E-base的n*E^0),而对于我们整个a[]数组,我们需要不断遍历它,一旦它满足任意位的系数大于1(可以用公式②将它的系数拆给两边的位),或者连续两个位系数大于等于1(可以用公式①将下一个位的系数加上前两个系数的小的那个值,而前两个系数则减去这个小的值)都可以用公式去进行优化,直到整个数组a[]中不能再由两个公式进行优化后,输出答案(输出时注意省略前导零和后续零,同时注意是否需要输出小数位)
代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 6 /* 7 E^n代表黄金分割数E的n次方幂 8 公式1:E^n = E^(n-1) + E^(n-2) 9 公式1推广:n*E^n = n*E^(n-1) + n*E^(n-2) 10 公式2:2*E^n = E^(n+1) + E^(n-2) 11 */ 12 int min(int a, int b){ 13 return a < b ? a : b; 14 } 15 16 int main(){ 17 int a[105]; 18 int n; 19 while(scanf("%d", &n) != EOF){ 20 memset(a, 0, sizeof(a)); 21 a[50] = n; 22 int flag = 1; 23 while(flag){ 24 flag = 0; 25 for(int i = 1; i <= 100; i++){ 26 if(a[i] > 1){ //如果系数大于1则根据公式2将系数分给高位和低位的系数,直到本身系数为0或1 27 a[i+1] += a[i]/2; 28 a[i-2] += a[i]/2; 29 a[i] %= 2; 30 flag = 1; //一旦执行过这个步骤则说明高位和低位的系数发生变化,则可能出现系数大于1或连续1出现 31 } 32 if(a[i-1] && a[i-2]){ //先调用公式1推广,将两个连续大于等于1的系数中的最小值附加给a[i] 33 int temp = min(a[i-1], a[i-2]); 34 a[i-1] -= temp; 35 a[i-2] -= temp; 36 a[i] += temp; 37 // a[i-1]--; //这里有个问题就是如果写成注释里的代码TL超时 38 // a[i-2]--; 39 // a[i]++; 40 flag = 1; //一旦a[i]增加,则a[i]有可能大于1,或者与其他相邻的数构成了连续1的情况 41 } 42 } 43 } 44 int point = 0; 45 for(int i = 49; i >= 1; i--){ 46 if(a[i] == 1){ 47 point = 1; 48 break; 49 } 50 } 51 //输出时前导0和后缀0不输出,同时注意是否需要小数点 52 int front = 0; 53 int back = 0; 54 for(int i = 100; i >= 50; i--){ 55 if(a[i] == 0 && front == 0){ //省略前导零 56 continue; 57 } 58 if(a[i] == 1) front = 1; 59 printf("%d", a[i]); 60 } 61 for(int i = 1; i <= 49; i++){ //找到末尾最后一个1的位置back记录 62 if(a[i] == 1){ 63 back = i; 64 break; 65 } 66 } 67 if(point){ 68 printf("."); 69 for(int i = 49; i >= back; i--) printf("%d", a[i]); 70 } 71 printf("\n"); 72 } 73 return 0; 74 }
如果有任何意见请在评论区积极留言