1 条题解
-
0
题解:Basically Speaking(P1546)
一、题目分析
本题要求实现数制转换程序,核心任务是将一个数从任意进制(2-16)转换为另一种进制(2-16),并按7位右对齐格式输出。关键要点包括:
- 输入数可能包含数字0-9和字母A-F(对应10-15)
- 转换后结果长度超过7位时输出"ERROR"
- 结果需右对齐,左侧补空格至7位
二、代码解析(C语言实现)
#include <stdio.h> #include <algorithm> #include <string.h> using namespace std; const int maxn = 1e5 + 5; char a[maxn]; // 存储输入的原进制数 char b[maxn]; // 存储转换后的目标进制数 // 字符转数字(A-F对应10-15,0-9对应0-9) int change(char c) { if (c == 'A') return 10; else if (c == 'B') return 11; else if (c == 'C') return 12; else if (c == 'D') return 13; else if (c == 'E') return 14; else if (c == 'F') return 15; else return c - '0'; } // 数字转字符(10-15对应A-F,0-9对应0-9) int change1(int n) { if (n == 10) return 'A'; else if (n == 11) return 'B'; else if (n == 12) return 'C'; else if (n == 13) return 'D'; else if (n == 14) return 'E'; else if (n == 15) return 'F'; else return n + '0'; } // 计算n的len次方(用于原进制转十进制) int pow(int n, int len) { int sum = 1; for (int i = 1; i <= len; i++) { sum *= n; } return sum; } int main() { int basc1, basc2; // 原进制和目标进制 while (scanf("%s", a) != EOF) { scanf("%d %d", &basc1, &basc2); int len = strlen(a); int sum = 0; // 原进制转十进制(核心步骤) for (int i = 0; i < len; i++) { sum += change(a[i]) * pow(basc1, len - 1 - i); } // 十进制转目标进制(除基取余法) int r, k = 0; while (sum > 0) { r = sum % basc2; b[k++] = change1(r); sum /= basc2; } // 结果长度检查 if (k > 7) { printf(" ERROR\n"); continue; } // 右对齐输出:先补空格,再输出结果(逆序) for (int i = 1; i <= 7 - k; i++) { printf(" "); } for (int i = k - 1; i >= 0; i--) { printf("%c", b[i]); } printf("\n"); } return 0; }
三、关键步骤解析
-
原进制转十进制
采用按位展开法:
对于原进制数 ( N = d_0d_1d_2\cdots d_{n-1} ),其十进制值为:
[ N_{10} = \sum_{i=0}^{n-1} d_i \times \text{basc1}^{n-1-i} ]
例如,二进制数1111000的计算过程:
[ 1 \times 2^6 + 1 \times 2^5 + 1 \times 2^4 + 1 \times 2^3 + 0 \times 2^2 + 0 \times 2^1 + 0 \times 2^0 = 120 ]
代码中通过将字符转换为对应数值,再乘以权值累加。 -
十进制转目标进制
采用除基取余法:
不断将十进制数除以目标进制基数,记录余数,直到商为0。余数逆序排列即为目标进制数。
例如,十进制120转十六进制:
[ 120 \div 16 = 7 \text{ 余 } 8 \quad \Rightarrow \quad 78_{16} ]
代码中通过取余,将余数转换为对应字符。 -
右对齐处理
- 若结果长度,输出"ERROR"(固定7字符,左补2空格)
- 否则,先输出个空格,再逆序输出结果(因取余顺序与实际数位顺序相反)
四、易错点与优化
- 数值范围问题
代码中使用类型存储中间结果,但当原进制数较大时(如16进制的ABCD),可能溢出。实际应使用或大数处理,但本题样例未超出范围(2^31-1=2147483647)。 - 输入合法性检查
代码未验证输入数是否合法(如八进制数包含8-9),实际应添加校验:若某字符对应的数值≥原进制基数,则输入无效。
五、样例验证
以输入行为例:
- 原进制转十进制
四进制数12312的各位权值计算:
[ 1 \times 4^4 + 2 \times 4^3 + 3 \times 4^2 + 1 \times 4^1 + 2 \times 4^0 = 256 + 128 + 48 + 4 + 2 = 438 ] - 十进制转二进制
438 ÷ 2 = 219 余 0
219 ÷ 2 = 109 余 1
109 ÷ 2 = 54 余 1
54 ÷ 2 = 27 余 0
27 ÷ 2 = 13 余 1
13 ÷ 2 = 6 余 1
6 ÷ 2 = 3 余 0
3 ÷ 2 = 1 余 1
1 ÷ 2 = 0 余 1
余数逆序为(11位),长度超过7,输出"ERROR"。
六、改进方向
- 大数处理:使用字符串存储中间结果,避免整数溢出
- 直接进制转换:跳过十进制中间步骤,直接进行进制转换(如二进制转十六进制可按4位分组)
- 合法性校验:添加输入数合法性检查,确保每个字符对应数值小于原进制基数
- 1
信息
- ID
- 547
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者