题目描述
16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法——Vigenère 密码。Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为南军所广泛使用。 在密码学中,我们称需要加密的信息为明文,用 M 表示;称加密后的信息为密文,用 C 表示;而密钥是一种参数,是将明文转换为密文或将密文转换为明文的算法中输入的数据,
记为 k。 在 Vigenère 密码中,密钥 k 是一个字母串,k=k1k2…kn。当明文 M=m1m2…mn 时,得到的密文 C=c1c2…cn,其中 ci=mi®ki,运算®的规则如下表所示
输入
Vigenère 加密在操作时需要注意:
1. ®运算忽略参与运算的字母的大小写,并保持字母在明文 M 中的大小写形式;
2. 当明文 M 的长度大于密钥 k 的长度时,将密钥 k 重复使用。
例如,明文 M=Helloworld,密钥 k=abc 时,密文 C=Hfnlpyosnd。
明文 | H | e | l | l | o | w | o | r | l | d |
密钥 | a | b | c | a | b | c | a | b | c | a |
密文 | H | f | n | l | p | y | o | s | n | d |
输入文件名为 vigenere.in。
输入共 2 行。
第一行为一个字符串,表示密钥 k,长度不超过 100,其中仅包含大小写字母。第二行
为一个字符串,表示经加密后的密文,长度不超过 1000,其中仅包含大小写字母。
输出
输出共 1 行,一个字符串,表示输入密钥和密文所对应的明文。
样例输入
ComleteVictory
Yvqgpxaimmklongnzfwpvxmniytm
样例输出
Wherethereisawillthereisaway
*********************************************************
顿时觉得只可意会不可言传……
从题目的描述来看,从明文转为密文的方式就是那一张表,假设表为一张坐标图,则有横轴与纵轴之分,把明文作为横轴,密钥作为纵轴(反着也行),给出了密钥和密文,将密钥和明文的字母对上去,找到的字母就是当前明文中字母的密文。
接下来为找规律
我理解的规律为:密文字母=明文字母+(密钥字母在字母表中的标号-1)
假设H为明文字母,a为密钥,则H+(1-1)=H
假设e为明文字母,b为密钥,则e+(2-1)=f
因为在解码表中,横轴与纵轴均为递增顺序,设明文不变,密钥的ascii码越大,密文ascii码也越大,而密钥增长多少,密文也就增长多少。
【注意】此仅为明文化为密文的规律,而题目是给密文求明文,所以规律要反过来:明文字母=密文字母-(密钥字母在字母表中的编号-1)。
因为密文和明文的大小写必须一致,所以鄙人采取了判断一个输出一个的方法
将密钥化为数字,即密钥在字母表中的编号-1
然后再用密文去减(鄙人在此处耗费了不少时间,要是密文减密钥的数字小于了字母a,就要取两者差的绝对值再用z去减,大写也一样,反正得考虑)。
减好了的数字就可以输出来了
题解至此完,下面一栏为代码(为了完整一点还是贴上来)
*********************************************************
#include<iostream>
#include<cstring>
#include<cstdio>
#include<fstream>
#define MAXN 1100
#define MAXK 110
using namespace std;
char yue[MAXK],miwen[MAXN]; //密钥,密文
int main()
{
//freopen("vigenere.in","r",stdin);
//freopen("vigenere.out","w",stdout);
scanf("%s",yue);
scanf("%s",miwen);
int a;
int l=strlen(yue); //密钥长度
int ll=strlen(miwen); //密文长度
for(int i=0;i<ll;i++)
{
char x=yue[i%l]; //当前要使用的密钥字母
if(miwen[i]>='a'&&x<='Z')x+=32; //使密钥和密文的大小写一致
if(miwen[i]<='Z'&&x>='a')x-=32; //同上(些许麻烦可改进)
if(x>='a') a=x-'a';
else a=x-'A'; //密钥在字母表中的编号-1
int j=miwen[i]-x; //是否不够减
if(j<0&&miwen[i]>='a')miwen[i]='z'+j+1;//是否不够减
else if(j<0&&miwen[i]>='A') miwen[i]='Z'+j+1; //是否不够减
else miwen[i]-=a;
cout<<miwen[i];
}
return 0;
}