POJ-2159(Ancient Cipher)

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

猜你喜欢

转载自www.cnblogs.com/Diligent-Memory/p/10243323.html