Playfair 加密

题目真的好长但是意思很简单

89.加密 (15分)
C时间限制:3 毫秒 | C内存限制:3000 Kb
题目内容:
一种Playfair密码变种加密方法如下:首先选择一个密钥单词(称为pair)(字母不重复,且都为小写字母),然后与字母表中
其他字母一起填入至一个5x5的方阵中,填入方法如下:
1.首先按行填入密钥串。
2.紧接其后,按字母序按行填入不在密钥串中的字母。
3.由于方阵中只有25个位置,最后剩下的那个字母则不需变换。
如果密钥为youandme,则该方阵如下:
y o u a n
d m e b c
f g h i j
k l p q r
s t v w x
在加密一对字母时,如am,在方阵中找到以这两个字母为顶点的矩形:
o u a
m e b

这对字母的加密字母为该矩形的另一对顶点,如本例中为ob。
请设计程序,使用上述方法对输入串进行加密,并输出加密后的串。
另外有如下规定:
1、一对一对取字母,如果最后只剩下一个字母,则不变换,直接放入加密串中;
2、如果一对字母中的两个字母相同,则不变换,直接放入加密串中;
3、如果一对字母中有一个字母不在正方形中,则不变换,直接放入加密串中;
4、如果字母对出现在方阵中的同一行或同一列,如df或hi,则只需简单对调这两个字母,即变换为fd或ih;
5、如果在正方形中能够找到以字母对为顶点的矩形,假如字母对为am,则该矩形的另一对顶点字母中,与a同行的字母应在前
面,在上例中应是ob;同样若待变换的字母对为ta,则变换后的字母对应为wo;
6、本程序中输入串均为小写字母,并不含标点、空格或其它字符。
解密方法与加密相同,即对加密后的字符串再加密,将得到原始串。
输入描述
从控制台输入两行字符串,第一行为密钥单词(长度小于等于25,字母不重复,且都为小写字母),第二行为待加密字符串(长度
小于等于50),两行字符串末尾都有一个回车换行符,并且两行字符串均为小写字母,不含其它字符。

输出描述
在标准输出上输出加密后的字符串。

输入样例
youandme
welcometohangzhou

输出样例
vbrmmomvugnagzguu

样例解释:

y  o u  a n
d m e  b c
f  g  h  i   j
k  l  p  q  r
s t  v  w x

welcometohangzhou

(一对一对找)找到对应的矩阵,输出另一个对角上面的字母,

如果其中一个字母不在矩阵中,原样输出

如果在同行或者同列,位置对调

如果剩最后一个字母,原样输出

we --> vb   lc-->rm  om -->mo  et-->mv  oh-->ug     an-->na    gz-->gz   ho-->gu   u-->u

#include <stdio.h>
#include <string.h>
char s1[26];
char str[55];   
char s[5][5];  //加密矩阵 
int a[27];
typedef struct{
    int x, y; //记录字母的横纵坐标 
}P;
P p[27]; 
int main(){
    scanf("%s%s", s1, str);
    memset(a, 0, sizeof a);
    int i = 0; 
    while(s1[i]){
        int d = s1[i] - 'a';
        a[d] = 1;
        i++;
    }
    int k = 0, len = strlen(s1);
    int f = 0;
    for(int i = 0; i < 5; i++){
        for(int j = 0; j < 5; j++){
            if(k < len){
                s[i][j] = s1[k];
                k++;
            }else{
                while(a[f] && f <= 25){ //循环结束时 a[f] = 0 
                    f++;
                }
                char c = f + 'a';
                s[i][j] = c;
                f++;
            }
        }
    }
    
    memset(a, 0, sizeof a);
    for(int i = 0; i < 5; i++){
        for(int j = 0; j < 5; j++){
            int d = s[i][j] - 'a';
            p[d].x = i; p[d].y = j;
            a[d] = 1;//判断是否出现过 
        }
    }
    
    
    i = 0; len = strlen(str);
    while(str[i]){
        if(i == len - 1){//最后一个单着
            printf("%c", str[i]); 
            i++;
        }else{
            //找到横纵坐标
            int d1 = str[i] - 'a';
            int d2 = str[i+1] - 'a';
            if(a[d1] && a[d2]){//就是都在加密矩阵中 
                int x1 = p[d1].x, y1 = p[d1].y;
                int x2 = p[d2].x, y2 = p[d2].y;
                //如果在同一列
                if(y1 == y2){
                    printf("%c%c", str[i+1], str[i]);
                } else{
                    printf("%c%c", s[x1][y2], s[x2][y1]);
                }
            }else{
                printf("%c%c", str[i], str[i+1]);
            } 
            i += 2;
        }
    }
    return 0;
} 
View Code