题意翻译
考虑下面的01串序列:
0,00,01,10,000,001,010,011,100,101,110,0000,0001,···,1101,1110,00000,···
首先是长度为1的串,然后是长度为2的串,依此类推。如果看成二进制,相同长度的后一个串等于前一个串加1。注意上述序列中不存在全为1的串。你的任务是是编写一个解码程序。
输入格式:可能有多组数据,对于每组数据,首先输入一个编码头,则上述序列的每个串依次对应编码头的每一个字符。接下来是编码文本(可能有多行组成,你应当把它们拼成一个长长的01串)。编码文本由多个小节组成,每个小节的前三个数字代表小节中每个编码的长度(用二进制表示),然后是各个字符的编码,以全1结束(例如,编码长度为2的小节以11结束)。编码文本以编码长度为000的小节结束。
输出格式:对于每组数据,输出其编码文本解码后的结果。
感谢@hedwig 提供的翻译
输入输出样例
输入 #1
TNM AEIOU
0010101100011
1010001001110110011
11000
$#**\
0100000101101100011100101000
输出 #1
TAN ME
##*\$
思路
题目的主要难点是如何按要求读取字符,如何读取二进制数,如何处理回车空格的特殊符号,还有如何完成符号和二进制之间的对应关系.参考紫书答案完成的代码.
代码
#include <stdio.h>
#include <string.h>
// PDF中给出了二进制数最多7位
char code[8][1 << 8];
// 函数功能:得到有效字符
char readChar() {
char ch;
// 使用循环屏蔽掉回车对getchar的影响.
while (1) {
ch = getchar();
// 直到找到不是回车的字符才退出函数
if (ch != '\n' && ch != '\r') {
return ch;
}
}
}
// 函数功能:完成二进制数对字符的对应
int readHead() {
char c;
// 注意初始化
memset(code, 0, sizeof(code));
c = readChar();
// 返回0
if (c == EOF) {
return 0;
}
// 第一个需要单独写处理, 屏蔽掉回车对输入的影响.
code[1][0] = c;
for (int i = 2; i < 8; i++) {
// 得到m
int m = (1 << i) - 1;
for (int j = 0; j < m; j++) {
if ((c = getchar()) == '\n') {
return 1;
}
code[i][j] = c;
}
}
return 1;
}
int readInt(int t) {
int v = 0;
char c;
// 按长度读取二进制数,并转换为十进制
for (int i = 0; i < t; i++) {
c = readChar();
v = v * 2 + (c - '0');
}
return v;
}
int main() {
while (readHead()) {
while(1) {
// 确定读取的长度
int len = readInt(3);
// 长度为0则代表本次文本结束
if (len == 0) {
break;
}
while (1) {
int n = readInt(len);
// 判断是不是小节结束标志
if (n == ((1 << len) - 1)) {
break;
}
printf("%c", code[len][n]);
}
}
// 注意格式
printf("\n");
}
return 0;
}
总结
这道题是对着紫书答案写的,看了一遍答案尝试自己去实现,结果一直出bug,又对着答案调了好久才AC,很多细节的地方需要注意.