例74 柱狀加密
問題描述
柱狀加密方案是使用密鑰對訊息(或明文)中的字母進行置亂,如下例所示,
假設密鑰是“BATBOY”,訊息明文是“MEET ME BY The OLD OAK TREE”,由于密鑰有6個字母,我們將訊息(忽略空格和標點符號)寫在一個有6列的網格中,根據需要用隨機的額外字母填充,結果如下:
MEETME
BYTHEO
LDOAKT
REENTH
在這里,我們用NTH填充了訊息,現在,密文是按列生成的,但列的列印順序由密鑰中的字母決定,因為密鑰中的A是字母表中第一個字母,所以第2列首先輸出,下一個字母B出現兩次,在這種情況下,先輸出最左邊的列(第1列),然后輸出第4列,之后,繼續按字母O、T、Y的順序輸出第5、3、6列,由于列的輸出順序是2、1、4、5、3、6,所以,密文為EYDEMBLRTHANMEKTETOEEOTH,
撰寫程式,根據給定的密鑰和密文,解密得到明文,
輸入
輸入包括多組測驗用例,每組測驗用例有兩行,第一個輸入為給定密鑰,該密鑰不超過10個字符,由大寫字母組成,第二行是密文,長度不超過100個字符,全部也由大寫字母組成,密鑰THEEND表示輸入結束,在這種情況下,將沒有密文跟隨,
輸出
對于每個測驗用例,輸出解密后的明文,
輸入樣例
BATBOY
EYDEMBLRTHANMEKTETOEEOTH
HUMDING
EIAAHEBXOIFWEHRXONNAALRSUMNREDEXCTLFTVEXPEDARTAXNAARYIEX
THEEND
輸出樣例
MEETMEBYTHEOLDOAKTREENTH
ONCEUPONATIMEINALANDFARFARAWAYTHERELIVEDTHREEBEARSXXXXXX
(1)編程思路,
先定義結構體
struct Elem
{
char ch;
int index;
};
其中,成員分量ch表示密鑰中的某個字母,index表示該字母對應的列號,
定義結構體陣列struct Elem letter[15],輸入密鑰后,將密鑰中的每個字母及該字母對應的列號保存為陣列letter中的一個元素,將陣列letter按成員分量字符ch從小到大排序,這樣,加密時列的順序也就得到了,將這個加密列號的順序保存到陣列int map[15];中,其中map[0]的值就是加密時所取的第1個列的列號,
加密時,密文是按列生成的,加密所用的矩陣行數row=(密文的長度)/(密鑰的長度),
設輸入的密文字串為cipher,則解密時,依次從該字串對應的矩陣中按行的順序,在每行中按加密密鑰指定的列號順序(已求得并存入map陣列中),取出字符順序填入到明文字串中即可,這個處理程序對應的回圈為
n=0;
for (i=0; i<row; i++)
{
for (j = 0; j <key_len; j++)
plain[n++]=cipher[i + map[j] * row];
}
plain[n]='\0';
(2)源程式,
#include <stdio.h>
#include <string.h>
struct Elem
{
char ch;
int index;
};
int main()
{
struct Elem letter[15],t;
char key[15],cipher[105],plain[105];
int key_len,map[15];
int i,j,n,row;
while (gets(key), strcmp(key, "THEEND")!=0)
{
gets(cipher);
key_len = strlen(key);
for (i = 0; i < key_len; i++)
{
letter[i].ch = key[i];
letter[i].index = i;
}
for (i=0;i<key_len-1;i++)
for (j=0;j<key_len-1-i;j++)
if (letter[j].ch>letter[j+1].ch)
{ t=letter[j]; letter[j]=letter[j+1]; letter[j+1]=t; }
for (i = 0; i<key_len; i++)
map[letter[i].index] = i;
row = strlen(cipher) / key_len;
n=0;
for (i=0; i<row; i++)
{
for (j = 0; j <key_len; j++)
plain[n++]=cipher[i + map[j] * row];
}
plain[n]='\0';
printf("%s\n",plain);
}
return 0;
}
習題74
74-1 資訊加密
問題描述
Mo和Larry發明了一種資訊加密方法,他們首先決定好列數,然后將資訊(只包含字母)從上往下依次填入各列,并在末尾補充一些隨機字母使其成為一個完整的字母矩陣,例如,若資訊是“There's no place like home on a snowy night”并且有5列,Mo會寫成:
t o i o y
h p k n n
e l e a i
r a h s g
e c o n h
s e m o t
n l e w x
注意Mo只會填入字母,且全部是小寫形式,在這個例子中,Mo用字母“x”填充了資訊使之成為一個完整的矩陣,當然他使用任何字母都是可以的,
Mo根據這個矩陣重寫資訊:首先從左到右寫下第一行,然后從右到左寫下第二行,再從左到右寫下第三行……以此左右交替地從上到下寫下各行字母,形成新的字串,這樣,例子中的資訊就被加密為:toioynnkpheleaigshareconhtomesnlewx,
你的作業是幫助Larry從加密后的資訊中還原出原始資訊(包括填充的字母),
輸入
第一行包含一個整數(范圍2到20),表示使用的列數,
第二行是一個長度不超過200的字串,
輸出
一行,即原始資訊,
輸入樣例
5
toioynnkpheleaigshareconhtomesnlewx
輸出樣例
theresnoplacelikehomeonasnowynightx
(1)編程思路,
定義二維字串陣列char mess[101][21]來保存密文字串所對應的字符矩陣,
先將輸入的密文字串中的每個字符按照先從左到右,然后再從右到左的順序逐行依次填入到陣列mess中,之后按列序優先的方式(每列從上到下)依次輸出mess陣列中的每個字符,就是解密后的原文,
(2)源程式,
#include <stdio.h>
int main()
{
char mess[101][21],src[201];
int row,col,i,j,d; // d代表方向,1從左向右,0從右向左
scanf("%d",&col);
scanf("%s",src);
i=0,row=0,j=-1,d=1;
while (src[i]!='\0')
{
if (d==1)
{
j++;
if (j==col)
{ row++; j=col-1; d=0; }
}
else
{
j--;
if (j==-1)
{ row++; j=0; d=1; }
}
mess[row][j]=src[i];
i++;
}
for (j=0;j<col;j++)
for (i=0;i<=row;i++)
printf("%c",mess[i][j]);
printf("\n");
return 0;
}
74-2 變換加密
問題描述
密碼學涉及秘密通信的方法,這些方法將訊息(明文)轉換為偽裝形式(密文),這樣,除了預期的接收者,看到密文的人將無法識別明文,將明文轉換為密文是加密;將密文轉換為明文就是解密,變換是一種簡單的加密方法,要求發送方和接收方都同意一個密鑰K,它是一個正整數,
變換加密方法使用四個陣列:明文plaintext和密文ciphertext是字符陣列,而明碼plaincode和密碼ciphercode是整數陣列,所有陣列的長度都是n,其中n是要加密的訊息的長度,陣列的下標起始為零,因此下標編號從0到n-1,對于這個問題,所有訊息(明文)中將只包含小寫字母、句點和下劃線(表示空格),
要加密的訊息以明文形式存盤,給定密鑰K,加密方法如下所示,首先根據以下規則將明文中的字母轉換為明文中的整數碼:'_'=0,'a'=1,'b'=2,'z'=26和'.'=27,接下來,根據以下公式將每個明碼轉換為加密密碼:對于從0到n-1的所有i,
ciphercode[i] = (plaincode[K*i mod n] - i) mod 28.,
(這里x mod y是x除以y時的正余數,例如,3 mod 7=3、22 mod 8=6和-1 mod 28=27,如果結果為負,要加上y,)最后,根據上面列出的規則將密碼中的代碼轉換回密文中的字母,
使用密鑰K=5對明文資訊“cat”加密程序如下:
陣列下標 0 1 2
明文plaintext c a t
明碼plaincode 3 1 20
密碼ciphercode 3 19 27
密文ciphertext c s .
撰寫一個可以解密的程式,即給定密鑰K,將密文轉換回原始明文,
輸入
輸入包含一個或多個測驗用例,后跟一行,該行僅包含表示檔案結束的數字0,每個測驗用例占一行,由密鑰K、空格和一條至少包含一個且最多70個字符的密文組成,密鑰K將是不大于300的正整數,
輸出
對于每個測驗用例,在一行上輸出對應的明文,
輸入樣例
5 cs.
101 thqqxw.lui.qswer
3 b_ylxmhzjsys.virpbkr
0
輸出樣例
cat
this_is_a_secret
beware._dogs_barking
(1)編程思路,
按題目的描述定義4個陣列,按加密程序的描述進行相應處理即可,
(2)源程式,
#include <stdio.h>
#include <string.h>
int mod(int a,int b)
{
return (a%b+b)%b;
}
int main()
{
char plaintext[75],ciphertext[75];
int plaincode[75],ciphercode[75];
int k,i,len;
while (scanf("%d",&k) && k!=0)
{
scanf("%s",ciphertext);
len=strlen(ciphertext);
for (i=0;ciphertext[i]!='\0';i++)
{
if (ciphertext[i]>='a' && ciphertext[i]<='z')
ciphercode[i]=ciphertext[i]-'a'+1;
else if (ciphertext[i]=='_')
ciphercode[i]=0;
else if (ciphertext[i]=='.')
ciphercode[i]=27;
}
for (i=0;i<len;i++)
{
plaincode[mod(k*i,len)]=mod(ciphercode[i]+i,28);
}
for (i=0;i<len;i++)
if (plaincode[i]>=1 && plaincode[i]<=26)
plaintext[i]=plaincode[i]-1+'a';
else if (plaincode[i]==0)
plaintext[i]='_';
else
plaintext[i]='.';
plaintext[len]='\0';
printf("%s\n",plaintext);
}
return 0;
}
74-3 訊息解密
問題描述
Alice向Bob發來了一潭訓亂的資訊,Bob請你進行破譯,Alice發送訊息使用的置亂方法如下:
1)獲取一條非空訊息M,其中包含英文字母表中的字母、數字、逗號、點、引號(’)、空格和換行符,最后一個字符不是空格,例如,考慮下面的資訊M
In Sneffels craterem descende audas
viator, et terrestre centrum attinges.
2)選擇一個整數K(0<K≤訊息M的長度),并向M添加尾隨空格,以使生成的訊息M’的長度是K的最小倍數,例如,對于K=19和上面的訊息,其中M的長度為74(包括M包含的8個空格和換行符),向M添加兩個尾隨空格,生成長度為76的訊息M',
3)將M'中的所有空格替換為字符“_”(下劃線),將M'中的所有換行符替換為“\”(反斜杠),然后反轉訊息如下:
__.segnitta_murtnec_ertserret_te_,rotaiv\sadua_ednecsed_meretarc_sleffenS_nI
4)將步驟3的結果寫入一個長度為(M'的長度)/K行和K列的表格中,例如,上面的訊息M’被寫入一個76/19=4行19列的表中,如下所示:

5)Alice將與表中的行相對應的字串作為加密訊息M的片段發向Bob,所發送資訊的4個片段是:
_etmneet_t\udsmt_fS
_gtuerr_,asaneeasf_
.narctrtria_edrrlen
si_t_seeovdec_ecenI
撰寫一個程式,破譯按上述方式加密的非空訊息,在加密之前,訊息的長度最多為1000個字符,包括空格和換行符,
輸入
輸入包括多組測驗用例,每個測驗用例對應一條加密訊息,一個測驗用例以整數n開始,該整數顯示被加密訊息的片段數,并以指定片段的n個字串繼續,其順序與加密程序第4步表中出現的順序相同,輸入資料片段以空格分隔,輸入以檔案結尾結束,
輸出
解密后的資訊必須列印在標準輸出上,從一行開始,后面必須有空行,如下面的輸入/輸出樣例所示,
輸入樣例
4 _etmneet_t\udsmt_fS
_gtuerr_,asaneeasf_
.narctrtria_edrrlen
si_t_seeovdec_ecenI
11 e n r e V _ s e l u J
輸出樣例
In Sneffels craterem descende audas
viator, et terrestre centrum attinges.
Jules Verne
(1)編程思路,
將輸入的加密資訊片段存放到二維陣列中,由于加密時實際上是將明文字串從右至左,從下至上存入二維表格中的,因此解密是將二維陣列中保存的字符也按從右至左,從下至上依次取出保存在結果字串中即可,保存的同時字符“_”變成空格,“\”變成回車符“\n”,最后去掉尾部多添加的空格,
(2)源程式,
#include <stdio.h>
#include <string.H>
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
char ch[1001][1001];
char res[1001];
memset(res,0,sizeof(res));
int i,j;
for (i=0;i<n;i++)
{
scanf("%s",ch[i]);
}
int len=strlen(ch[0]);
int pos=0;
for (i=len-1;i>=0;i--)
{
for (j=n-1;j>=0;j--)
{
if (ch[j][i]=='_') res[pos++]=' ';
else if (ch[j][i]=='\\') res[pos++]='\n';
else res[pos++]=ch[j][i];
}
}
for (i=pos-1;res[i]==' ';i--) // 去掉尾部多添加的空格
res[i]='\0';
printf("%s\n\n",res);
}
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/438608.html
標籤:C
