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 } 

 

posted on 2019-08-16 13:00  白泽talk  阅读(291)  评论(0编辑  收藏  举报