• POJ2159Ancient Cipher


    转载请注明出处:優YoU http://user.qzone.qq.com/289065406/blog/1299062729

     

    PS:本题稍微说一下题意(当时有点发牢骚的感觉,O(∩_∩)O哈哈~)

    一种我认为是比较符合现实的解题思路,但是总是Wrong Answer

     

    咋看之下确实是被题目忽悠了,一般思路都是先对置换解密,再对乱序解密,但是题目所给出的乱序码只有10个,<2, 1, 5, 4, 3, 7, 6, 10, 9, 8>,输入要求却是不大于100的字符串,这里就显示出了矛盾所在:没有10之后的乱序码根本无法解密!!

     

    初看之下这道题目确实是无理取闹,但是从矛盾中同时也给予了我们提示:我们一开始的思路就是错误的!!

     

    试想想,实际中对于一段密文,即使我们知道它是使用了凯撒加密(就是置换加密)乱序加密的组合,但是我们却很难得出乱序加密的“顺序”,因为它很可能是随机的!

    但是凯撒加密这一环确实可以被破解出来 的,通过循环!因为凯撒加密一开始就脱离不了alphabet!而且对于每一个字母它的置换规则都是一样的,例如AC,A往后+2所得,那么B的加密也只能+2BD,在alphabet末尾的字母就要卷回alphabet开头。那么通过循环去测试A+i的数字i,也不过是26次而已!

    那么乱序加密又如何破解?答案是基本没有办法,除非知道了乱序码。但是可以通过间接手段去验证。下面将叙述。

     

    本题其实已经给出了凯撒加密的数字i,就是i=1,这样就省去破解凯撒加密的时间了。

    输入密文猜测的明文后,先破解密文中凯撒加密的部分,那么现在的密文和猜测的明文区别就在于顺序性!

    虽然我们不知道乱序码,但是正因为不知道乱序码,我们有更加简单的方法去判定密文和明文是否一致!我们把密文和明文都视为乱序,然后分别对它们的所有字母进行排序!

    现在只需要比较排序后的两段文字,就可以判定密文猜测的明文是否一致了。

     

     

     

     

    正确解题思路

    虽然方法更简单,但是正常人很难想到会是这个思路 

    不必理会凯撒加密和乱序加密,默认都是不知道解码方法。

    那么唯一判断 密文 猜测的明文 是否一致的方法就是 把出现频数相同的字母归结为一类(而不必理会组成这一类中的各个字母类型是否一致,但是字母的数量必须一致,例如密文中ABCD都分别出现一次,把他们归为一类,明文中BNUJ也都分别出现一次,把他们也归结为一类,那么这时认为ABCDBNUJ这两类是等价的;但若密文中ABCD都分别出现一次,而明文中出现一次的只有 KIO三个字母,那么 ABCDKIO是不等价的),并将出现的次数进行排序,再比较两个频数序列是否相同即可(比较的是频数列,而不是字母列),相同说明可由明文串经变换得出密文串(看这口气好像是说“至于怎么变换出来就不是我们该考虑的问题了,我们管不着!”  )

     

     1 //Memory   Time 
    2 //188K 16MS
    3
    4 #include<iostream>
    5 #include<string>
    6 #include<algorithm>
    7 using namespace std;
    8
    9 int main(void)
    10 {
    11 int i;
    12 int cipher[26],clear[26];
    13 memset(cipher,0,sizeof(cipher)); //对长度为sizeof(cipher)=int*26=104的连续内存空间cipher全部元素初始化为0
    14 memset(clear,0,sizeof(clear));
    15 string input;
    16 cin>>input;
    17 for(i=0;i<input.length();i++)
    18 {
    19 cipher[input[i]-'A']++;
    20 }
    21 cin>>input;
    22 for(i=0;i<input.length();i++)
    23 {
    24 clear[input[i]-'A']++;
    25 }
    26 sort(cipher,cipher+26); // 标准库自带排序函数sort(ip_start,ip_end) 对某连续的地址段的对象内容进行升序快排(从小到大),<algorithm>
    27 sort(clear,clear+26); //亦即sort(ip_start+m,ip_start+n),其中为从ip_start+m开始(包括ip_start+m)对第n到第m个对象进行排序
    28 for(i=0;i<26;i++)
    29 if(cipher[i]!=clear[i])
    30 {
    31 cout<<"NO"<<endl;
    32 return 0;
    33 }
    34 cout<<"YES"<<endl;
    35 return 0;
    36 }

    [ EXP技术分享博客 ] 版权所有,转载请注明出处: http://exp-blog.com
  • 相关阅读:
    MSIL指令速查表
    .NET中的内存管理,GC机制,内存释放过程,各种内存释放方法
    程序员学专业英语
    C#入门不简单(上网找beginning c# objects时看到的一些话,很有同感)
    关掉在打开的做法很有必要
    视图刷新
    创建 平面求交点
    3dmas 的硬显示 这个就是其中既各个 最后两个是 对应显示操作的
    这句话是我在渲染 程序贴图用到的代码
    设置到基础层
  • 原文地址:https://www.cnblogs.com/lyy289065406/p/2120475.html
Copyright © 2020-2023  润新知