1402Vigenère密码(Noip2012提高组第1题)

Posted TFLSNOI

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1402Vigenère密码(Noip2012提高组第1题)相关的知识,希望对你有一定的参考价值。

维吉尼亚密码:人们在单一恺撒密码的基础上扩展出多表密码,称为“维吉尼亚”密码。该方法最早记录在吉奥万·巴蒂斯塔·贝拉索( Giovan Battista Bellaso)于1553年所著的书《吉奥万·巴蒂斯塔·贝拉索先生的密码》(意大利语:La cifra del. Sig. Giovan Battista Bellaso)中。技术分享图片

我大概花了1.5h写出的代码,老同志写代码慢,你们写估计40-50min↓↓↓↓  缺点:审题不清,代码量大,算法不够严谨,代码运行时间长。。。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 using namespace std;
 6 char a[30][30];
 7 char k[1200],m[1200];
 8 /*step3:密钥和密文来查找明文函数的编写*/
 9 char chazhao(char c1,char c2)
10 {
11     int x,y;
12     //下面循环实现行查找 
13     for(int i=1;i<=26;i++)
14     {
15         if(a[i][1]==toupper(c1))
16         {
17             x=i;
18             break;
19         }
20     } 
21     //下面循环实现通过行号和密文结果来找明文 
22     for(int i=1;i<=26;i++)
23     {
24         if(a[x][i]==toupper(c2))
25         {
26         y=i;
27         break;    
28         }
29     }
30     //大小写对应 
31     if(c2>=A&&c2<=Z)return char(A+y-1);
32     else return char(a+y-1);
33 }
34 int main()
35 {
36     char c=A;
37     for(int i=1;i<=26;i++)
38     {
39         for(int j=1;j<=26;j++)
40         {    
41             a[i][j]=c;
42             c++;
43             if(c==[)c=A;
44         }
45         c++;
46         if(c==[)c=A;    
47     }
48     /*step1:构造运算规则表,完成之后可以单独测试*/
49     gets(k);
50     gets(m);
51     int lk=strlen(k),lm=strlen(m);
52     int kk=lk,n=0;
53     while(kk<lm)
54     {
55         k[kk++]=k[n++];
56         if(n==lk)n=0;
57     }
58     /*step2:让密钥和密文长度一样的放在两个数组中,这样就可以方便下一步一次循环实现*/
59     for(int i=0;i<lm;i++)cout<<chazhao(k[i],m[i]);
60     return 0;
61 } 

网上其他题解↓↓↓↓↓↓↓简短,代码量少。。。算法严谨

本表指 一对密钥与原文可以加密成密文,现在要翻译密文,也就是知道对应的点,也知道了y轴坐标,求x轴坐标。
1.当密文≥密钥时,我们发现数据是依次递增的,则此时ans[i]= miwen[i]-key[j]+‘a‘
2.当密文<密钥时,数据由最右端向左依次递减,此时ans[i]= ‘z‘-(key[j]-miwen[i]-1)
j的意义在后面。
注意这里还有一个易错点,密钥的长度可能小于密文的长度,那么当密钥较短时就要运用循环多次使用此密钥
int j=0;
 并且在每次循环后
j++;
if(j==strlen(key))
      j=0;
最后通过miwen_x[i]的值将原文的大小写形式恢复原样
这样就解决此问题了
本题总思路:
1.读入密钥、密文并转换成小写(大写也可),同时记录密文的大小写情况
2. 运用算法算出原文
3.通过大小写情况恢复原文的大小写

技术分享图片
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>

int change(int i)//大小写转换 
{
    return (i>=A&&i<=Z)?i+a-A:i;
}


int main()
{
    char key[120];
    char miwen[1200];
    int miwen_x[1200];//密文大小写 1小写 2大写 
    scanf("%s %s",key,miwen);
    int len=strlen(key);
    for(int i=0;i<=len-1;i++)
        key[i]=change(key[i]);
    for(int i=0;i<=strlen(miwen)-1;i++)
    {
        if(miwen[i]>=A&&miwen[i]<=Z)
            miwen_x[i]=2;
        else
            miwen_x[i]=1;
        miwen[i]=change(miwen[i]);
    }
    
    char ans[1200];
    int j=0;
    for(int i=0;i<=strlen(miwen)-1;i++)
    {
        if(miwen[i]>=key[j])
            ans[i]=miwen[i]-key[j]+a;
        else
            ans[i]=z-(key[j]-miwen[i]-1);
        if(miwen_x[i]==2)
            ans[i]=ans[i]-(a-A);
        j++;
        if(j==len)
            j=0;
    }
    ans[strlen(miwen)]=0;
    printf("%s",ans);
    
            
    return 0;
}
View Code

 敲黑板结论:读题规划算法比写代码更重要。。。
















以上是关于1402Vigenère密码(Noip2012提高组第1题)的主要内容,如果未能解决你的问题,请参考以下文章

Vigenère密码

Vigenère密码

Vigenère密码

Vigenère密码

codevs1197 Vigenère密码

Vigenère 密码(luogu 1079)