题解 洛谷P1071【潜伏者】
题目链接:https://www.luogu.org/problem/P1071
题意概括:给你一段原来截获的英文密码和与之对应的明文,如果密码表非F♂A法,输出”Failed” ,否则翻译现在给你的一句密文并输出。(所有字母均为大写)
有两种情况视为密码表非法:
1、 所有信息扫描完毕,但发现有字母在原信息中没有出现(密码表脱漏)。
2、 扫描中发现掌握的信息里有明显的自相矛盾或错误(密码表错乱)。
这道题主要思想可以利用数组打表,首先我们定义一个数组code作为密码表
然后进行密码表制作,比如一个密文是“DDYAKIOI”,明文是“SSDPOLKL”(首先声明一点,这只是为了便于理解写的短样例,这个样例实际上已经非法了)
可见code[‘D’](即code[68])为’S’,code[‘Y’]为’D’,以此类推。
现有密文为”DOAI”,根据一对一原则,翻译出来就是”SKPL”。
下面详细解释一下两种非法情况:
一、密码表脱漏
很好理解,就是有的密文位没有相对应的明文字母。排除方法:因为本题常数较小,考虑使用直接扫描的方法判断
二、密码表错乱
这种情况又分为两种小情况:一对多和多对一
一对多:一个密文位对应多个明文字母。排除方法:压入明文制表过程中判断,发现与当前占位被不同字母抢占则判定非法
多对一:多个密文对应一个明文字母。排除方法:全表从头至尾扫描,发现与当前明文占位不同明文相同的则判定非法
(此图大雾)
接下来是愉快的贴代码时间,是好孩子的话就不要复制题解呢……(微笑)
- 1 //Stand up for the faith!
- 2 #include<bits/stdc++.h>
- 3 using namespace std;
- 4 #define ll long long
- 5
- 6 char myst[400],word[400];
- 7 char sent[400],code[400];
- 8 //分别代表密文、明文、需译语句、密码表
- 9 signed main(void)
- 10 {
- 11 scanf("%s%s",myst,word);
- 12 int len1=strlen(myst);
- 13 int len2=strlen(word);
- 14 for(int i=0;i<=400;i++) code[i]='\0'; //初始化密码表,方便判断脱漏
- 15 if(len1!=len2||len1<26) //初步判断
- 16 {
- 17 puts("Failed");return 0;
- 18 }
- 19 /*此处明确几点:
- 20 1、如果密文和明文长度不等,100%无法一一对应,视为非法
- 21 2、如果长度少于26,一定无法A-Z全部对应,直接非法
- 22 3、如果长度多于26,不一定非法(比如有两次等价对应)*/
- 23 for(int i=0;i<len1;i++)
- 24 {
- 25 if(code[myst[i]]>='A'&&code[myst[i]]<='Z'&&code[myst[i]]!=word[i])
- 26 //判断不同字母对应相同密字(此前已有其他不同的字母占位)
- 27 {
- 28 puts("Failed");return 0;
- 29 }
- 30 for(int j='A';j<='Z';j++)
- 31 {
- 32 if(code[j]==word[i]&&j!=myst[i])
- 33 //判断相同字母对应不同密字(在不同占位上含有相同的字母)
- 34 {
- 35 puts("Failed");return 0;
- 36 }
- 37 }
- 38 code[myst[i]]=word[i];
- 39 }
- 40 for(int i='A';i<='Z';i++)
- 41 {
- 42 if(code[i]=='\0') //判断是否有字母没有出现
- 43 {
- 44 puts("Failed");return 0;
- 45 }
- 46 }
- 47 scanf("%s",sent);
- 48 int len=strlen(sent);
- 49 for(int i=0;i<len;i++)
- 50 {
- 51 cout<<code[sent[i]]; //逐个输出对应字母
- 52 }
- 53 }