目录
题目描述:
内存限制:128 MB 时间限制:1.000 S
评测方式:文本比较 命题人:admin
题目描述
摩尔斯编码采用变长的点号“.”和短划线“-”序列来代表字符。实际编码时,电文中的字符用空格隔开。表4.1是摩尔斯编码中各字符对应的编码。
注意,在上表中点号和短划线有4个组合没有采用。在本题中,将这四种组合分配给以下的字符:
下划线:..-- 点号:---. 逗号:.-.- 问号:----
因此,电文“ACM_GREATER_NY_REGION”被编码为:.- -.-. -- ..-- --. .-. . .- - . .-. ..-- -. -.-- ..-- .-. . --. .. --- -.
Ohaver基于摩尔斯编码提出了一种加密方法。这种方法的思路是去掉字符间的空格,并且在编码后给出每个字符编码的长度。例如电文“ACM”编码为“.--.-.--242”。
Ohaver的加密(解密也是一样的)方法分为3个步骤:
(1)将原文转换成摩尔斯编码,去掉字符间的空格,然后把每个字符长度的信息添加在后面;
(2)将表示各字符长度的字符串反转;
(3)按照反转后的各字符长度,解释点号和短划线序列,得到密文。
例如,假设密文为“AKADTOF_IBOETATUK_IJN”,解密步骤如下:
(1)将密文转换为摩尔斯编码,去掉字符间的空格,添加各字符长度组成的字符串,得到“.--.-.--..----..-...--..-...---.-.--..--.-..--...----.232313442431121334242”;
(2)将字符长度字符串反转,得到“242433121134244313232”;
(3)对字符长度字符串反转后的编码字符串,用摩尔斯编码解释该字符串,得到原文“ACM_GREATER_NY_REGION”。
本题目的目的是实现Ohaver的解密算法。
输入
输入文件中包含多个测试数据。输入文件的第1行是一个整数n,表示测试数据的个数。每个测试数据占一行,为一个用Ohaver加密算法加密后的密文。每个密文中允许出现的符号为:大写字母,下划线、逗号,点号和问号。密文长度不超过100个字符。
输出
对输入文件中的每个密文,首先输出密文的序号,然后是冒号和空格,最后是解码后的原文。
样例输入 复制
5
AKADTOF_IBOETATUK_IJN
PUEL
QEWOISE.EIVCAEFNRXTBELYTGD.
?EJHUT.TSMYGW?EJHOT
DSU.XFNCJEVE.OE_UJDXNO_YHU?VIDWDHPDJIKXZT?E
样例输出 复制
1: ACM_GREATER_NY_REGION
2: PERL
3: QUOTH_THE_RAVEN,_NEVERMORE.
4: TO_BE_OR_NOT_TO_BE?
5: THE_QUICK_BROWN_FOX_JUMPS_OVER_THE_LAZY_DOG
题解(思路在题目中已给出,这里是实现的方法):
注释版:
#include <bits/stdc++.h>
using namespace std;
//用一个二维数组存放所有的摩尔斯编码
//从A到Z,然后依次是下划线(26)、点号(27)、逗号(28)和问号(29)
char code[31][5]={".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","..--","---.",".-.-","----"};
//存放30个字符
char character[31]="ABCDEFGHIJKLMNOPQRSTUVWXYZ_.,?";
//存放每个字符对应的摩斯编码长度
//空间开大点没啥问题
int len[35]={2,4,4,3,1,4,3,4,2,4,3,4,2,2,3,4,4,3,3,1,3,4,3,4,4,4,4,4,4,4};
int n,i,j;
//存放读入的密文
char s[105];
int main()
{
scanf("%d",&n);
//接收回车键
getchar();
//c语言使用getchar();来接受回车键
//c++可以直接用cin >> n;
for(i=1;i<=n;i++)
{
//读入密文
scanf("%s",s);
//原先的话或许可以使用c语言中的gets(),但现在这并不安全
//存放摩尔斯编码
char data[600]="\0";
//存放字符所对应的编码长度
char msglen[105]="\0";
//下面进行摩尔斯编码
for(j=0;s[j]!='\0';j++)
{
//c++特性,与c不同的是,这里可以再用一个i
for(int i=0;i<30;i++){
//这里用我们之前做的字母表去判断是哪个字符
if(character[i]==s[j]){
//将code[i]指向的字符串加到data的末尾
strcat(data,code[i]);
//存放字符对应的编码长度
msglen[j]=len[i];
//找到了就退出
break;
}
}
}
//输出序号,这里随着全局变量i在循环中变大而变大
printf("%d: ",i);
int tag=0;
char tmp[10]="\0";
//反着取字符长度数组中的值,相当于反转
for(j=strlen(msglen)-1;j>=0;j--)
{
//根据msglen中的长度,在text中取出相应长度的编码,然后翻译成字母
int tmplen=msglen[j];
//从data的tag开始处取tmplen个字符存放到tmp中去
strncpy(tmp, data + tag, tmplen);
//这里我们用tag记一下我们data读取到了哪里
//如果不记录的话我们下一次还会从头开始取
tag+=tmplen;
//下一步用来告诉程序,这个临时的数组的结尾在哪里,很必要
tmp[tmplen]='\0';
//根据tmp中的内容找到对应的字符
for(int k = 0;k < 30;k++)
{
//找到了就取出字符
if(strcmp(tmp,code[k])==0)
{
printf("%c",character[k]);
break;
}
}
}
//每次都换行
printf("\n");
}
return 0;
}
纯代码:
#include <stdio.h>
#include <string.h>
char code[31][5]={".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","..--","---.",".-.-","----"};
char character[31]="ABCDEFGHIJKLMNOPQRSTUVWXYZ_.,?";
int len[35]={2,4,4,3,1,4,3,4,2,4,3,4,2,2,3,4,4,3,3,1,3,4,3,4,4,4,4,4,4,4};
int n,i,j;
char s[200];
int main()
{
scanf("%d",&n);
getchar();
for(i=1;i<=n;i++)
{
scanf("%s",s);
char data[600]="\0";
char msglen[105]="\0";
for(j=0;s[j]!='\0';j++)
{
for(int i=0;i<30;i++){
if(character[i]==s[j]){
strcat(data,code[i]);
msglen[j]=len[i];
break;
}
}
}
printf("%d: ",i);
int tag=0;
char tmp[10]="\0";
for(j=strlen(msglen)-1;j>=0;j--)
{
int tmplen=msglen[j];
strncpy(tmp, data + tag, tmplen);
tag+=tmplen;
tmp[tmplen]='\0';
for(int k = 0;k < 30;k++)
{
if(strcmp(tmp,code[k])==0)
{
printf("%c",character[k]);
break;
}
}
}
printf("\n");
}
return 0;
}