信息解码(Message Decoding)ACM/ICPC World Finals 1991,UVa 213

在这里插入图片描述

审题

清楚编码文本是怎样生成的,自己研究!基本是能看懂的!
读一遍题目,不知道要干啥,看得懂怎么解密加密,不会写代码,具体写什么东西?
1.划重点:
在这里插入图片描述
2.解决重点:
①你要编写的是一个解码程序,这个解码程序是个什么样子的?

你不需要给出任何的输入语句,输入是测试数据时写好的,例如:

$#**\
0100000101101100011100101000

上解码工具,你的代码要做到对上面的数据进行解析:

##*\$

你编写代码时就想象屏幕上就有测试数据,你直接调用合适的读取函数读取就行!

②解决多行问题?

上面的那串$#**\字符是编码头;长长的01串就是编码文本,这个编码文本可能是多行,意思就是可以出现换行,即:

$#**\
01000001011
011000111
00101
000

当然这个换行是按照题目所规定的规律换行的,每到小节结束另一个小节开始可以换行,那么怎么解决读这些代码的时候可以处理换行了?

写一个函数readchar();
不断被读取代码,当遇到\n \t的时候,就跳过,继续往下读取,当读取到非换行符的时候即文件结束符EOF时,就跳出循环。

int readchar(){
	int ch=getchar();
	while(ch!='\n'&&ch!='\r')	return ch;
/*
	在Windows中:
	'\r' 回车,回到当前行的行首,而不会换到下一行,如果接着输出的话,本行以前的内容会被逐一覆盖;
	'\n' 换行,换到当前位置的下一行,而不会回到行首;
	 所以需要用到&&
*/
}

③每个小节的前3个数字代表小节中的编码长度?

意思是,每一个小节的前三个数字,例如010,转化成十进制是2,即以下的01串每2个长度保存了该小节中的一个字符信息,直到读到特殊意义的串就停止字符解析。

重点在于理解,这种你该解析的串有多少种长度类型了?前3个数字代表小节中的编码长度,很容易想到二进制,有多少种二进制组合,抛去题目说的000有特殊意义外,剩下有7个,即001、010、011、100、101、110、111,转换成十进制后,分别代表小节中长度为1、2、3、4、5、6、7的串代表一个字符!意思就是,这种该解析的串的范围在1-7个长度

④怎样储存这些01串?

观察01串,0、00、01、000、001、010、011、100、101、110……
长为1的串:转成十进制0
长为2的串:转成十进制01
长为3的串:转成十进制0123456
长为4的串:转成十进制0123456789101112131415
……
仔细看这些标黄数字,怎样存储?且要维护顺序。
二维数组!这个二维数组就已经维护了顺序生成的01串编码头
int code[len][value]
为什么是整型?
1.你所对应的01串可换算成十进制的具体值
2.你的密码字符虽然是char类型,但注意一点,它并没有汉字,也就是说它只是一些普通的字符而已,都可以映射成相应的ASCII码,你存进int类型数组中时,便自动的跟你转换成了相应ASCII码,当你要输出时,只需要以%c的形式输出里面的相应ASCII码,便是对应码字符!

len代表该串长度,value代表串的对应十进制值
这个二位数组初始化空间多大?
②中已经详细的说了,01串只有7中长度类型,1-7,所以len=8(0-7);value代表串的对应十进制值,不难想到肯定要大于等于最大的二进制表达数,即当01串长度为7且全为1的时候最大,27,约定初始化空间稍大于数据规模。
int code[7][1<<8]

架构(伪代码解题思路)

1.读第一行的密码字符,一个一个读,并按照顺序存储到codes数组中;<<readcodes()>>
2.读接下来可能有多行的01编码密码串。
按照题目要求读:①首先读前三个串,通过函数转换成十进制数值len<<readint(3)>>;判断len是否是特殊意义的串000代表编码密码串结束!
② 其次去读指定len数值长度的01串,换成十进制数值value<<readint(len)>>,判断value是否是小节结束的特殊值,不是则利用,是则break去读下一小节,即又从①开始了!
③从codes数组找对应字符,即codes[len][value]!输出<<putchar(codes[len][value])>>
④循环①②③,直到碰壁①的条件!

int main(){
	
	while( readcodes() ){
	
		for( ; ; ){
			int len=readint(3); 
			if(len==0)	break;//编码密码串结束标志位000
			
			for( ; ; ){
				int value=readint(len);
				if(value==(1<<len)-1)	break;//每小节结束标志位,全1
				putchar(codes[len][value]); 
			}
			
		} 
			
	} 
	return 0;
} 

大概解题思路缕完,可以先自己尝试着敲一遍代码,完善细节!
注意readcodes()函数中的细节

代码

#include<stdio.h>
#include<string.h>

int readcodes();//处理第一行要加密的字符串,改换成相应编码头存进数组 
int readint(int);//将指定长度01串转换成整型 
char readchar();//读串 

int codes[8][1<<8];

int readint(int s){
	int number=0;
	while(s--)	number=number*2+readchar()-'0';//进制转换
	return number;
}

int readcodes(){
	memset(codes,0,sizeof(codes));	//每次都需要初始化密码字符数组
	codes[1][0]=readchar();//先存储第一个,之后的密码字符便可按照规律循环存储
	
	int i,j;
	for(i=2;i<=7;i++){
		for(j=0;j<(1<<i)-1;j++){
			int ch=getchar();
			if(ch==EOF)	return 0;//文件结束符
			if(ch=='\n'||ch=='\r')	return 1;//读到了空格或者转行,终止函数,不用存进密码字符数组中
			codes[i][j]=ch;
		}
	}
	return 1;
}

int readchar(){
	int ch=getchar();
	while(ch!='\n'&&ch!='\r')	return ch;//用于针对密码文本多行的情况,如果时换行继续往下读再返回字符
}

int main(){
	
	while( readcodes() ){
		for( ; ; ){
			int len=readint(3); 
			if(len==0)	break;
			for( ; ; ){
				int value=readint(len);
				if(value==(1<<len)-1)	break;
				putchar(codes[len][value]); //把存进去的相应ASCII码输出转换成字符
			}
		} 
		printf("\n");	
	} 
	
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值