NENU OJ Problem 1120 摩尔斯编码

目录

题目描述:

题解(思路在题目中已给出,这里是实现的方法):

注释版:

纯代码:


题目描述:

内存限制: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;
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值