算法竞赛入门经典(第二版) | 例题4-4 信息解码 (紫皮书牛啤!)(UVa213,Message Decoding)

大意:

二进制编码中取前三位,得到编码长度为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 了就不管了,应该多看看别人的解法。

发布了73 篇原创文章 · 获赞 61 · 访问量 4790

猜你喜欢

转载自blog.csdn.net/weixin_43899069/article/details/104342885