北大Poj 2159

Ancient Cipher

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 37410   Accepted: 12176

Description

Ancient Roman empire had a strong government system with various departments, including a secret service department. Important documents were sent between provinces and the capital in encrypted form to prevent eavesdropping. The most popular ciphers in those times were so called substitution cipher and permutation cipher. 
Substitution cipher changes all occurrences of each letter to some other letter. Substitutes for all letters must be different. For some letters substitute letter may coincide with the original letter. For example, applying substitution cipher that changes all letters from 'A' to 'Y' to the next ones in the alphabet, and changes 'Z' to 'A', to the message "VICTORIOUS" one gets the message "WJDUPSJPVT". 
Permutation cipher applies some permutation to the letters of the message. For example, applying the permutation <2, 1, 5, 4, 3, 7, 6, 10, 9, 8> to the message "VICTORIOUS" one gets the message "IVOTCIRSUO". 
It was quickly noticed that being applied separately, both substitution cipher and permutation cipher were rather weak. But when being combined, they were strong enough for those times. Thus, the most important messages were first encrypted using substitution cipher, and then the result was encrypted using permutation cipher. Encrypting the message "VICTORIOUS" with the combination of the ciphers described above one gets the message "JWPUDJSTVP". 
Archeologists have recently found the message engraved on a stone plate. At the first glance it seemed completely meaningless, so it was suggested that the message was encrypted with some substitution and permutation ciphers. They have conjectured the possible text of the original message that was encrypted, and now they want to check their conjecture. They need a computer program to do it, so you have to write one.

Input

Input contains two lines. The first line contains the message engraved on the plate. Before encrypting, all spaces and punctuation marks were removed, so the encrypted message contains only capital letters of the English alphabet. The second line contains the original message that is conjectured to be encrypted in the message on the first line. It also contains only capital letters of the English alphabet. 
The lengths of both lines of the input are equal and do not exceed 100.

Output

Output "YES" if the message on the first line of the input file could be the result of encrypting the message on the second line, or "NO" in the other case.

Sample Input

JWPUDJSTVP
VICTORIOUS

Sample Output

YES

Source

Northeastern Europe 2004


题目很长,而且这道题,理解题意非常关键

  • 介绍了 substitution 和 permutation 两种加密方法,但实际上,permutation 需要给出每个字母的位置,题目中只有在例子中给出了10个字母的一种情况,但注意 Input 中的一句话:“The lengths of both lines of the input are equal and do not exceed 100.” ,很明显,给出的字符串可能是任意不超过100的长度。这时再品味下 Output 里 “could be the result” 的意味,题意就呼之欲出了——只要给出的原始信息(第二行)做 substitution 后各字母频数与 加密信息(第一行) 一致,就说明 “could be the result”;
  • 理解了题意后,开始编程。首先读入两行数据。这里可以先做一个简单判断,如果给出的两个字符串长度不一样,那么肯定是没办法匹配的;
  • 接着对原始信息(第二行)做 substitution 处理,这里要注意字母 'Z' 的特殊性,不能像其他字母一样简单++,还是置为 'A'。(这点题目中也有提示);
  • 然后我创建了两个数组a、b,用来统计两个字符串各字母的频数,并初始化其值均为0(频数初值)。这里我是用两个 for 循环处理的。内循环 i 遍历整个字符串,外循环 j 遍历26个英文字母,通过 orig[i]=='A'+j 来判断,最终 orig[0] 就是 ‘A’ 的频数, orig[1] 是 ‘B’ 的频数,以此类推。conj[i]类似;
  • 最后比较数组a和b的值,从头比较到尾,其值需全部相等,才能说明频数一致。否则,如果没到最后就出现不相等,那就直接 “break”了,j的值不为26,自然输出 “NO”。

综上,自己写的代码是这样的:

//10.5
// VICTORIOUS -> substitution
// WJDUPSJPVT -> permutation <2, 1, 5, 4, 3, 7, 6, 10, 9, 8>
// JWPUDJSTVP
#include <iostream>
#include <string>
using namespace std;
int main (void){
    string orig,conj;
    int i,j;

    while(cin>>orig>>conj){
        size_t len1 = conj.length();
        size_t len2 = orig.length();
        if(len1!=len2) {
            cout<<"NO"<<endl;
        }
        else{
            int a[26]={0};
            int b[26]={0};
            
            for(i=0;i<len1;i++){
                if(conj[i]=='Z') conj[i]='A';
                else conj[i]++;
            }
            
            for(j=0;j<26;j++){
                for(i=0;i<len2;i++){
                    if(orig[i]=='A'+j) {
                        b[j]++;
                    }
                }
            }
            
            for(j=0;j<26;j++){
                for(i=0;i<len1;i++){
                    if(conj[i]=='A'+j) {
                        a[j]++;
                    }
                }
            }
            
            
            for(j=0;j<26;j++){
                if(a[j]!=b[j]){
                    break;
                }
            }
            if(j == 26) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
    
    }
    return 0;
}

自己测试没有问题,但一直是WRONG ANSWER,很无奈。

最后看了下别人的,用了排序,很简洁,也ACCEPT了,贴出来参考下吧。(然鹅还是不知道我的哪错了)

#include <iostream>
#include <algorithm>

using namespace std;

int main() {
    int a[26]={0};
    int b[26]={0};
    int ntmp;
    int i=0;
    char origin[101],encrypt[101];
    
    while(cin>>encrypt>>origin){
        while((ntmp = encrypt[i++] - 'A') >= 0 && ntmp < 26)
            a[ntmp]++;
        i=0;
        while((ntmp = origin[i++] - 'A') >= 0 && ntmp < 26)
            b[ntmp]++;
        //sort
        sort(a, a+26);
        sort(b, b+26);
        // compare and judge
        for(i=0; i<26; i++){
            if(a[i] != b[i]){
                break;
            }
        }
        if(i == 26)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
        
    }
    return 0;
}

而且我没懂这个排序的必要。。。去掉这个排序就 WRONG ANSWER 了。。。

猜你喜欢

转载自blog.csdn.net/qq_36770641/article/details/82958527