藍橋杯 程序設計_7

        一種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 n

d m e b c

f g h i j

k l p q r

s t v w x

這對字母的加密字母爲該矩形的另一對頂點,如本例中爲ob

請設計程序,使用上述方法對輸入串進行加密,並輸出加密後的串。

另外有如下規定:

1一對一對取字母,如果最後只剩下一個字母,則不變換,直接放入加密串中;

2、如果一對字母中的兩個字母相同,則不變換,直接放入加密串中;

3、如果一對字母中有一個字母不在正方形中,則不變換,直接放入加密串中;

4、如果字母對出現在方陣中的同一行或同一列,如dfhi,則只需簡單對調這兩個字母,即變換爲fdih

5、如果在正方形中能夠找到以字母對爲頂點的矩形,假如字母對爲am,則該矩形的另一對頂點字母中,與a同行的字母應在前面,在上例中應是ob;同樣若待變換的字母對爲ta,則變換後的字母對應爲wo

6、本程序中輸入串均爲小寫字母,並不含標點、空格或其它字符。

解密方法與加密相同,即對加密後的字符串再加密,將得到原始串。

要求輸入形式如下:

從控制檯輸入兩行字符串,第一行爲密鑰單詞(長度小於等於25),第二行爲待加密字符串(長度小於等於50),兩行字符串末尾都有一個回車換行符,並且兩行字符串均爲小寫字母,不含其它字符。

在標準輸出上輸出加密後的字符串。

例如,若輸入:

youandme

welcometohangzhou

則表示輸入的密鑰單詞爲youandme,形成的正方形如上所示;待加密字符串爲welcometohangzhou。在正方形中可以找到以第一對字母we爲頂點的矩形,對應另一對頂點字母爲vb,因此加密後爲vb,同理可找到與字母對lc,et,oh,ho對應的頂點字母對。而字母對om位於上述正方形中的同一列,所以直接以顛倒這兩個字母來加密,即爲mo,字母對an同理。字母對gz中的z不在上述正方形中,因此原樣放到加密串中。最後剩一個字母u也原樣輸出。

因此輸出的結果爲:

vbrmmomvugnagzguu

分析:

純邏輯題,自頂向下求解。先根據需求定義求解流程(順序),再根據每個流程定義函數(包括功能,參數),最後實現每個函數。

解:

#include <stdio.h>
#include <string.h>

#define KEY_X	5						//方陣行
#define KEY_Y	5						//方陣列
#define MAX_PAIR_NUM	KEY_X*KEY_Y		//方陣字符數
#define	MAX_STR	50						//字串最大字節數

typedef int		INT32;
typedef char	INT8;
typedef void	VOID;

/****************************************************************************
* 函數:CreatKey 															*
* 參數:pair:密鑰單詞.														*
*	   key:密鑰方陣.														*
*      keyPos:(字母-'a')在key中位置(距key首地址的位置).					*
* 返回值:無.																*
* 功能:生成密鑰方陣.														*
*****************************************************************************/
VOID CreatKey(INT8 *pair, INT8 key[][KEY_Y], INT8 *keyPos)
{
	INT32 i,j,k, np;
	INT32 c26, n;

	memset(keyPos, -1, 26);

	np = strlen(pair);

	//每個字母1bit
	c26 = 0;
	for(i=0; pair[i] != 0; i++)
		c26 |= (1<<(pair[i]-'a'));

	//生成密鑰方陣和keyPos
	k = 0;
	for(i=0; i<KEY_X; i++)
		for(j=0; j<KEY_Y; j++)
		{
			n = i*KEY_Y+j;
			if(n < np)
			{
				key[i][j] = pair[n];
				keyPos[key[i][j]-'a'] = n;
			}
			else
			{
				while(1 == ((c26 >> (k)) & 0x1))
					k++;

				key[i][j] = k+'a';
				keyPos[k] = n;
				k++;
			}
		}

/*
	printf("Key:\n");
	for(i=0; i<KEY_X; i++)
	{
		for(j=0; j<KEY_Y; j++)
		{
			printf("%c ", key[i][j]);
		}
		printf("\n");
	}

	printf("KeyPos:\n");
	for(i=0; i<26; i++)
	{
		printf("%c:%d ", i+'a', keyPos[i]);
		if(0 == (i+1)%KEY_Y)
			printf("\n");
	}
*/
}

/****************************************************************************
* 函數:Encrypt 																*
* 參數:str:待加密字串.														*
*      enstr:(out)密文.													*
*	   key:密鑰方陣.														*
*      keyPos:(字母-'a')在key中位置(距key首地址的位置).					*
* 返回值:無.																*
* 功能:加密字串str,並將密文保存在enstr.									*
*****************************************************************************/
VOID Encrypt(INT8 *str, INT8 *enstr, INT8 key[][KEY_Y], INT8 *keyPos)
{
	INT8 *p, *q;
	INT8 a, b;
	INT32 x1,y1,x2,y2;

	p = str;
	q = enstr;

	//一對一對取字母
	while(NULL != *(p+1))
	{
		a = *p++;
		b = *p++;
		a -= 'a';
		b -= 'a';

		//如果一對字母中的兩個字母相同,則不變換,直接放入加密串中
		//如果一對字母中有一個字母不在正方形中,則不變換,直接放入加密串中;
		if(a == b || -1 == keyPos[a] || -1 == keyPos[b])
		{
			*q++ = a+'a';
			*q++ = b+'a';
			continue;
		}

		x1 = keyPos[a]/KEY_Y;
		y1 = keyPos[a]%KEY_Y;

		x2 = keyPos[b]/KEY_Y;
		y2 = keyPos[b]%KEY_Y;

		//如果字母對出現在方陣中的同一行或同一列,如df或hi,則只需簡單對調這兩個字母,即變換爲fd或ih;
		if(x1 == x2 || y1 == y2)
		{
			*q++ = b+'a';
			*q++ = a+'a';
			continue;
		}

		//如果在正方形中能夠找到以字母對爲頂點的矩形,假如字母對爲am,則該矩形的另一對頂點字母中,與a同行的字母應在前面,在上例中應是ob;同樣若待變換的字母對爲ta,則變換後的字母對應爲wo;
		*q++ = key[x1][y2];
		*q++ = key[x2][y1];
	}

	//如果最後只剩下一個字母,則不變換,直接放入加密串中
	if(*p)
		*q++ = *p;

	*q = '\0';
}

INT32 main(INT32 argc, INT32 *argv[])
{
	INT8 pair[MAX_PAIR_NUM+1];	//密鑰單詞
	INT8 str[MAX_STR+1];		//待加密字串
	INT8 enstr[MAX_STR+1];		//加密後字串
	INT8 key[KEY_X][KEY_Y];		//密鑰方陣
	INT8 keyPos[26];			//(字母-'a')在key中位置(距key首地址的位置)

	printf("請輸入密鑰單詞(字母不重複,且都爲小寫字母)...\n");
	scanf("%s", pair);
	printf("請輸入待加密字串(長度小於等於50)...\n");
	scanf("%s", str);

	CreatKey(pair, key, keyPos);

	Encrypt(str, enstr, key, keyPos);
	printf("\n\nEncrypt:\n%s\n", enstr);

	Encrypt(enstr, str, key, keyPos);
	printf("Deciphering:\n%s\n", str);
	
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章