大意:
二进制编码中取前三位,得到编码长度为n(0<=n<=7), 按此长度重复截取编码中剩余部分(n位一截),直到读取n个1结束。再次取三位,长度为n,重复上述操作…直至n个1后接000,文本结束。
本题输出格式:若用回车分割出多行编码, 则编一行,输出一行。(注意英文原题)
题目(提交)链接→UVa-213
百度翻译→百度翻译
没使用过该网站的同学请猛戳这里→vJudge教程
分析:
1、循环1:用readcodes()函数读取编码字符,存入二维数组,二维数组横坐标为二进制位数,一位存第一行,二位存第二行… 形成表格。输入EOF则退出。
2、循环2:用readint()函数获取编码长度,若长度为0则退出,不为0则进入循环2
3、循环3:用readint()函数按长度截取编码,期间用readchar()函数跳过回车符,同时readint()函数将该二进制数转化为十进制,
查表,输出对应的字符,直至读出n个1,返回循环1,重复…
还不是很明白的同学。把代码中三段注释消除,将所有函数的头部标红,自己调试一遍就明白了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int readchar() { //处理编码文本可以由多行组成的情况,"跨行读字符",单独开辟函数。
for(;;) {
int ch = getchar();
if(ch != '\n' && ch != '\r') return ch; //一直读到非换行符为止。
}
}
int readint(int c) { //获取头部三位编码,并转化为十进制。
int v = 0;
while(c--) v = v * 2 + readchar() - '0'; //二进制转十进制核心代码。
return v;
}
int code[8][1<<8]; //将字符写入这里
int readcodes() { //将所有字母按其二进制编码顺序存入code ,第一行存一位、二行存3(1<<len-1)位..
memset(code, 0, sizeof(code)); //清空数组(二维数组也可同样清空)
code[1][0] = readchar(); //直接调到下一行读取,因为这一行只能有一个二进制数0(1表示结束)
for(int len = 2; len <= 7; len++) {
for(int i = 0; i < (1<<len)-1; i++) {
int ch = getchar();
if(ch == EOF) return 0;
if(ch == '\n' || ch == '\r') return 1;
code[len][i] = ch;
}
}
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 ) return;
printf("code[%d][%d] = %c\n", len, i, code[len][i]);
}
}
int main()
{ while(readcodes()) { //无法读取更多编码头时退出
// printcodes();
for(;;) {
int len = readint(3); //获取接下来的编码长度
if(len == 0) break; //如果为0,文本输入结束
// printf("len=%d\n", len);
for(;;) {
int v = readint(len); //按长度决定取几位
// printf("v=%d\n", v);
if(v == (1 << len)-1) break; //如果v等于全为1的二进制数,则表示结束。
putchar(code[len][v]);
}
}
putchar('\n');
}
return 0;
}
收获:
1、\r是回车符,其中r是return的缩写。回车符的作用是将当前位置移到本行的开头。
2、二维数组的清空方法。
3、将所有函数的头部都标红,就可以在调试时进入(调试技巧)。
4、二进制的表示方法。注意: 一定是(1<<len)-1; 1<<len-1等价于1<<(len-1)
5、进制之间转化函数(将文中2换成x。)
6、文件结束的判断;‘000’结束的判断;‘1’结束的判断;三步层层递进
7、紫皮书牛啤!我为紫皮书带盐!不接受反驳!
最后,分享一条大牛的建议(对笔者受益匪浅):平时在做题的时候,一定要寻找最优解,而不是 ac 了就不管了,应该多看看别人的解法。