Message Decoding UVa 213

输入

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值