【题目链接】
ybt 1855:【09NOIP提高组】潜伏者
OpenJudge NOI 1.7 11:潜伏者
洛谷 P1071 [NOIP2009 提高组] 潜伏者
【题目考点】
1. 字符串
2. ASCII码
【解题思路】
因为题中指明了:每个字母只对应一个唯一的“密字”,不同的字母对应不同的“密字”。因此明文字母和密文字母为一一对应的关系。
设数组ori与enc,初值都为’\0’。ori[i]指密文字母i对应的明文字母,enc[i]指明文字母i对应的密文字母。每找到新的一对对应关系:明文A对应密文B,则需要先检查明文A是否已经有对应的密文字母(enc[A]是否不为’\0’),以及密文B是否有对应的明文字母(ori[B]是否不为’\0’)。
- 如果二者都没有对应的字母,那么建立明文A与密文B的对应关系,让enc[A] = B,ori[B] = A。每建立一对关系,做一次计数。
- 如果A或B已经存在与其对应的字母,而且对应关系不为“明文A对应密文B”,那么输出Failed。
由于题目中有要求:如果发现存在某个(或某些)字母在原信息中没有出现,则破译失败。所以每个密文字母都要有与其对应的明文字母,对应关系数量必须得等于26。
最后统计关系数量,如果达到26,则使用已经构建好的明文密文关系做字符串解密。如果关系数量小于26,则输出Fail。
映射关系可以使用散列数组来记录,也可以使用map来记录。
【题解代码】
解法1:使用散列数组
#include<bits/stdc++.h>
using namespace std;
#define N 105
int main()
{
char s_e[N], s_o[N], s_n[N];//s_e:加密后字符串 s_o:原字符串 s_n:待加密字符串
char ori[128] = {}, enc[128] = {};//ori[i]:ASCII码为i的加密字符的原字符 enc[i]:ASCII码为i的原字符对应的加密字符 初值都为'\0'
cin >> s_e >> s_o >> s_n;
int l1 = strlen(s_e), l2 = strlen(s_n), cn = 0;//cn:已经确定的加密关系的个数
for(int i = 0; i < l1; ++i)
{
if(ori[s_e[i]] == '\0' && enc[s_o[i]] == '\0')//如果不存在s_e[i]对应的明文,同时不存在s_o[i]对应的密文
{//建立对应关系:明文s_o[i]对应密文s_e[i]
ori[s_e[i]] = s_o[i];
enc[s_o[i]] = s_e[i];
cn++;
}
else if(ori[s_e[i]] != s_o[i] || enc[s_o[i]] != s_e[i])//如果已有对应关系,且对应关系不为明文s_o[i]对应密文s_e[i]
{
cout << "Failed";
return 0;
}
}
if(cn != 26)//如果对应关系不足26对
{
cout << "Failed";
return 0;
}
for(int i = 0; i < l2; i++)//解密s_n字符串
cout << ori[s_n[i]];
return 0;
}
解法2:使用map
#include <bits/stdc++.h>
using namespace std;
int main()
{
map<char, char> eo, oe;//eo[a] = b:密文字符a对应原文字符b oe[a] = b:原文字符a对应密文字符b
string enc, ori, s;
cin >> enc >> ori >> s;
for(int i = 0; i < enc.length(); ++i)
{
if(eo.count(enc[i]) == 0 && oe.count(ori[i]) == 0)
{
eo[enc[i]] = ori[i];
oe[ori[i]] = enc[i];
}
else if(eo[enc[i]] != ori[i] || oe[ori[i]] != enc[i])//发生情况3:自相矛盾
{
cout << "Failed";
return 0;
}
}
if(eo.size() != 26)
{
cout << "Failed";
return 0;
}
for(int i = 0; i < s.length(); ++i)
s[i] = eo[s[i]];//密文转明文
cout << s;
return 0;
}