算法竞赛入门经典(紫书)第四章——Message Decoding UVA-213

14 篇文章 0 订阅

题意:
题目要求对给定的编码进行解密。
编码的规则是利用下面所示的 01 串

与给定的字符串相对应起来,如 AB#TANCnrtXc ,则能得到下面的信息:
0 - A
00 - B
01 - #
10 - T
000 - A
001 - N
010 - C
011 - n
100 - r
101 - t
110 - X
0000 - c
我们能够看到 01 串中全 1 的串不存在。

现在给出编码的格式如下:

现在要求翻译给出的 01 串。

思路:
我们可以用编码的位数和大小构成的有序对来描述上述信息,可以写成下面这样:
(1, 0) - A
(2, 0) - B
(2, 1) - #
(2, 2) - T
(3, 0) - A
(3, 1) - N
(3, 2) - C
(3, 3) - n
(3, 4) - r
(3, 5) - t
(3, 6) - X
(3, 7) - c
由上我们可以发现 (x, y)(x 代表位数,y 代表二进制数的大小)中的 0y2x1 0 ≤ y ≤ 2 x − 1
上面的有序对我们可以用 map 来记录,然后我们可以一个一个字符地读入 01 串,遇到换行就忽略它,其中一个信息节是一次外循环,信息节中的信息是一次内循环。

这里讲下自己原来的错误,自己一开始读取 01 串的思路不是一个一个字符地读入,而是把 01 串读入 char 的数组中再做处理,以当前 01 串的结尾是 000 为读入结束标志。用这种思路的时候总是出现 Runtime error,没找到明确的原因,暂时怀疑是出现了以下的情况导致的:
假设输入数据为
TNM AEIOU
010000
111000
按照以当前 01 串的结尾是 000 为读入结束标志的思路,当我读入 010000 时就结束了 01 串的读取,就可能导致后面的数据读入错乱了吧。事实上这个 01 串的信息节是这样的:010 00 01 11 000
在我成功用一个一个字符读入的思路后,发现把 01 串读入再处理的思路错误且复杂。。。所以 A 不出来的时候换个思路试试,说不定是当前的思路错了,只是自己没发现罢了。

下面对两个样例进行讲解:
样例一:
(1, 0) - T
(2, 0) - N
(2, 1) - M
(2, 2) - (空格)
(3, 0) - A
(3, 1) - E
(3, 2) - I
(3, 3) - O
(3, 4) - U

将输入的 01 串按编码格式分开来看:
001 0 1 //前三位表示编码只有 1 位,中间的 0 表示成位数和数字大小的有序对即 (1, 0) 表示信息 ‘T’,最后一个 1 表示结束
011 000 111 //前三位表示编码有 3 位,中间的 000,即 (3, 0) 表示 ‘A’,最后三个 1 表示结束
010 00 10 01 11 //前三位表示编码有 2 位,中间的 00 即 (2, 0) 表示 ‘N’,10 即 (2, 2) 表示 ’ ‘,01 即 (2, 1) 表示 ‘M’,最后的两个 1 表示结束
011 001 111 //前三位表示编码有 3 位,中间的 001 即 (3, 1) 表示 ‘E’,最后的三个 1 表示结束
000 //表示当前样例结束

这样整个输出即为 TAN ME

样例二:
(1, 0) - $
(2, 0) - #
(2, 1) - *
(2, 2) - *
(3, 0) - \

将输入的 01 串按编码格式分开来看:
010 00 00 10 11 //前三位表示编码有 2 位,中间的 00 即 (2, 0) 表示 ‘#’,00 即 (2, 0) 表示 ‘#’,10 即 (2, 2) 表示 ‘*’,最后的 11 表示结束
011 000 111 //前三位表示编码有 3 位,中间的 000 即 (3, 0) 表示 ‘\’,最后的 111 表示结束
001 0 1 //前三位表示编码有 1 位,中间的 0 即 (1, 0) 表示 ‘$’,最后的 1 表示结束
000 //表示样例的结束

这样整个输出就是 ##*\ $

注意:
1. 用 gets() 时注意前面是否留有换行符,有的话要提前 putchar() 掉。
2. 题目中说 key strings 的最大长度是 7 ,算了下这样 key strings 最多有 247 个,所以我下面代码的 ch 数组的长度是 250,要是长度比这个小就会 Runtime error 了。
下面稍微讲下 247 是怎样算出来的。
长度为 1 的 key 有 1 个,
长度为 2 的 key 有 3 个,
长度为 3 的 key 有 7 个,
长度为 4 的 key 有15 个……
这个规律能够看出是 ×2+1,所以有
1+3+7+15+31+63+127 = 247

代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<utility>
#include<vector>
#include<cmath>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
#include<sstream>
using namespace std;
typedef long long LL;

const int pw[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};

map<pair<int,int>, char> mp;
char ch[250];

int Get(int num)
{
    int ret = 0;
    char ch;
    for(int i=0; i<num; i++){
        ch = getchar();
        if(ch=='\n') i--;
        else{
            ret *= 2;
            ret += ch=='1'?1:0;
        }
    }
    return ret;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    while(gets(ch) != NULL){
        mp.clear();
        //printf("ch: %s\n", ch);

        int lentmp = strlen(ch);
        int w = 1, num = 0;
        //printf("mp:\n");
        for(int i=0; i<lentmp; i++){
            mp[make_pair(w, num)] = ch[i];
            //printf("(%d, %d) - %c\n", w, num, ch[i]);
            num++;
            if(num >= pw[w]-1){
                w++;
                num = 0;
            }
        }

        while((w=Get(3)) != 0){
            while((num=Get(w)) != pw[w]-1){
                putchar(mp[make_pair(w, num)]);
            }
        }
        putchar('\n');
        getchar();
    }
    return 0;
}

想看书上的源代码的话看这 (^▽^)
https://github.com/aoapc-book/aoapc-bac2nd

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值