输入
TNM AEIOU
0010101100011
1010001001110110011
11000
$#**\
0100000101101100011100101000
输出
TAN ME
##*\$
思路
输入的header中的每个字符与0, 00, 01, 10, … 一一对应,即T对应0, N对应00.
那么输入的数据可以使用一个二维数组来保存,其格式按照(以TNM AEIOU为例)
T n = 2^1- 1
N, M, (空格) n = 2^2 - 1
A, E, I, O, U n = 2^3 - 1
加密信息分成了多段,划分不按照两行区分,而是以开头的三个字符标明段内每次阅读的长度后,结尾处用与阅读长度相等的多个1来划分。比如一段开头是010,那么在这段信息内每次就只阅读2个字符,而结尾处则会用“11”来说明此段结束。
那么现在的问题则是如何将Header映射到数组中,以及怎么处理加密信息了。
Header映射
映射方面,使用两个for循环数组即可。
处理加密信息
在处理加密信息时,首先一个问题是如何处理’\n’ (or ‘\r’). 只需要一个辅助方法,每次通过这个方法来读取字符,而在这个辅助方法中,先读区一个字符,并判断其是否为’\n’,如果是就继续读,如果不是则放回当前已经读区了的字符。
第二个问题,则是如何处理二进制的转换并映射到信息中去。同样此处可以使用一个辅助方法,这个方法每次都接受一个参数,为要读取的长度。比如读取头一段信息的三个字符,即方法参数为3,010,那么每次读一个字符,然后减去’0’再乘上对应的2^i即可。这之后,只需要每次都读取由信息头段指定的长度就可以了,比如读了“001”,则返回1;这里每次得到的数字,可以看作二维数组的第二个参数,而第一个参数则是信息头段的长度。在这个例子中,是[2][1]. 同时每次读取时都判断,所读数字是否是多个1组成的信息段结尾。
代码
#include <string.h>
#include <stdio.h>
int code[8][1<<8];
int readchar(FILE *fin)
{
for (;;) {
int c = fgetc(fin);
if (c != '\n' && c != '\r') return c;
}
}
int readint(int n, FILE *fin)
{
int v = 0;
while (n--)
v = v*2 + (readchar(fin) - '0');
return v;
}
int readcodes(FILE *fin)
{
memset(code, 0, sizeof(code));
code[1][0] = readchar(fin);
for (int len=2; len<=7; ++len)
for (int i=0; i < (1<<len)-1; ++i) {
int c = fgetc(fin);
if (c == EOF) return 0;
if (c == '\n' || c == '\r') return 1;
code[len][i] = c;
}
return 1;
}
void printCodes()
{
for (int len=1; len<=7; ++len)
for (int i=0; i<(1<<len)-1; ++i) {
if (code[len][i] == 0) break;
printf("code[%d][%d] = %c\n", len, i, code[len][i]);
}
printf("\n");
}
int main()
{
FILE *fin, *fout;
fin = fopen("input.txt", "r");
fout = fopen("output.txt", "w");
while (readcodes(fin)) {
printCodes();
for (;;) {
int len = readint(3, fin);
if (len == 0) break;
for (;;) {
int v = readint(len, fin);
if (v == (1<<len)-1) break;
fputc(code[len][v], fout);
}
}
fputc('\n', fout);
}
return 0;
}