Ancient Cipher
POJ链接:http://poj.org/problem?id=2159
//原题是英文,我用谷歌翻译让大家更好的理解这题是意思,此题应该算是密钥问题里面简单的题^_^
描述
古罗马帝国拥有强大的政府体系,各部门包括一个秘密服务部门。各省和首都之间以加密形式发送重要文件,以防止窃听。那些时代最流行的密码是所谓的替换密码和置换密码。
替换密码将每个字母的所有出现更改为其他字母。所有字母的替代品必须不同。对于某些字母,替换字母可能与原始字母重合。例如,应用替换密码将所有字母从“A”更改为“Y”到字母表中的下一个字母,并将“Z”更改为“A”,将消息“VICTORIOUS”更改为“WJDUPSJPVT”。
置换密码对消息的字母应用一些置换。例如,将置换<2,1,5,4,3,7,6,10,9,8>应用于消息“VICTORIOUS”,得到消息“IVOTCIRSUO”。
很快就注意到,单独应用,替换密码和置换密码都相当弱。但是当它们合并时,它们在那些时候足够强大。因此,首先使用替换密码对最重要的消息进行加密,然后使用置换密码对结果进行加密。使用上述密码的组合加密消息“VICTORIOUS”,获得消息“JWPUDJSTVP”。
考古学家最近发现这条信息刻在石板上。乍一看它似乎完全没有意义,因此建议使用一些替换和置换密码对消息进行加密。他们推测了加密的原始邮件的可能文本,现在他们想检查他们的猜想。他们需要一个计算机程序来完成它,所以你必须写一个。
输入
输入包含两行。第一行包含刻在板上的信息。在加密之前,所有空格和标点符号都被删除,因此加密的邮件只包含英文字母的大写字母。第二行包含推测在第一行的消息中加密的原始消息。它还只包含英文字母的大写字母。
输入的两条线的长度相等,不超过100。
输出
如果输入文件第一行上的消息可能是第二行加密消息的结果,则输出“YES”,否则输出“NO”。
样本输入
JWPUDJSTVP
VICTORIOUS
样本输出
YES
解题思路:
此题中的某个字符串经过一些交换和替换的操作后,新产生的字符串相当于原码的编码,刚开始看感觉既交换还要替换相当复杂,其实只用看两个字符串每种字符出现的频率是否一致即可,我用一个表格给大家看清楚:
所有很容易看出规律,题目要求全是大写字母,更简单了一些(‘A’ 65 ~ ‘Z’ 90),可以将字符串每个元素减去‘A’,结果正好包含在字母序号(0~25)中,相当于数组的下标,遍历一遍统计好出现的次数,再用一个排序函数(最好从大到小排,比对时效率高一些),两个字符串的频率数组排序好之后,直接进行一一比对即可。
初版的代码:(用的是冒泡排序)
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #define N 100 5 #define S 27 6 char a[N], b[N]; 7 int count1[S], count2[S]; 8 void calculate() {//统计字符串中字符出现的频率 9 int len1 = strlen(a); 10 int len2 = strlen(b); 11 int count = 0; 12 for (int i = 0; i < len1; i++) { 13 if (a[i] >= 'A'&&a[i] <= 'Z') 14 { 15 count = a[i] - 'A'; 16 count1[count]++; 17 } 18 } 19 for (int j = 0; j < len2; j++) { 20 if (b[j] >= 'A'&&b[j] <= 'Z') 21 { 22 count = b[j] - 'A'; 23 count2[count]++; 24 } 25 } 26 } 27 void sort(int q[]) {//冒泡排序 28 int temp; 29 for (int i = 0; i < S - 1; ++i) 30 for (int j = 0; j < S - i - 1; ++j) 31 { 32 if (q[j] > q[j + 1]) 33 { 34 temp = q[j]; 35 q[j] = q[j + 1]; 36 q[j + 1] = temp; 37 } 38 } 39 } 40 int main() 41 { 42 gets(a); 43 gets(b); 44 calculate(); 45 sort(count1); 46 sort(count2); 47 int flag = 1; 48 for (int i = 0; i < S; i++) { 49 if (count1[i] != count2[i]) 50 { 51 flag = 0; 52 break; 53 } 54 } 55 if (flag == 1) 56 printf("YES\n"); 57 else 58 printf("NO\n"); 59 return 0; 60 }
其实还可以进行优化,不需要用两个字符串数组来存,只用一个字符数组即可,用完直接输入新的字符串替换原来的,排序改用快速排序,时间复杂度:O(nlogn)
优化后的代码:
1 #include<stdio.h> 2 #include<stdlib.h> 3 int compare(const void*a, const void*b) 4 { 5 int *pa = (int *)a; 6 int *pb = (int *)b; 7 return *pa - *pb;//从大到小来排 8 } 9 int main() 10 { 11 int i, a[27], b[27]; 12 char s[200]; 13 for (i = 0; i < 27; i++) 14 a[i] = b[i] = 0; 15 gets(s); 16 for (i = 0; s[i]; i++) 17 a[s[i] - 'A']++; 18 gets(s); 19 for (i = 0; s[i]; i++) 20 b[s[i] - 'A']++; 21 qsort(a, 27, sizeof(int), compare); 22 qsort(b, 27, sizeof(int), compare); 23 for (i = 0; i < 27; i++) 24 if (a[i] != b[i]) 25 break; 26 if (i > 26) 27 puts("YES\n"); 28 else 29 puts("NO\n"); 30 return 0; 31 }
以上代码均以AC,不知道大家做这题时先想到的是那个呢
欢迎大家评论,有什么疑惑或错误,望指出O(∩_∩)O