主頁 > 後端開發 > C語言程式設計100例之(73):Caesar 密碼

C語言程式設計100例之(73):Caesar 密碼

2022-03-07 06:11:38 後端開發

例73  Caesar 密碼

問題描述

Julius Caesar 生活在充滿危險和陰謀的年代,為了生存,他首次發明了密碼,用于軍隊的訊息傳遞,假設你是Caesar 軍團中的一名軍官,需要把Caesar 發送的訊息破譯出來、并提供給你的將軍,訊息加密的辦法是:對訊息原文中的每個字母,分別用該字母之后的第5個字母替換(例如:訊息原文中的每個字母A都分別替換成字母F),其他字符不變,并且訊息原文的所有字母都是大寫的,

密碼字母:A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

原文字母:V W X Y Z A B C D E F G H I J K L M N O P Q R S T U

輸入

最多不超過100個資料集組成,每個資料集由3部分組成:

起始行:START

密碼訊息:由1到200個字符組成一行,表示Caesar發出的一條訊息

結束行:END

在最后一個資料集之后,是另一行:ENDOFINPUT

輸出

每個資料集對應一行,是Caesar 的原始訊息,

輸入樣例

START

NS BFW, JAJSYX TK NRUTWYFSHJ FWJ YMJ WJXZQY TK YWNANFQ HFZXJX

END

START

N BTZQI WFYMJW GJ KNWXY NS F QNYYQJ NGJWNFS ANQQFLJ YMFS XJHTSI NS WTRJ

END

START

IFSLJW PSTBX KZQQ BJQQ YMFY HFJXFW NX RTWJ IFSLJWTZX YMFS MJ

END

ENDOFINPUT

輸出樣例

IN WAR, EVENTS OF IMPORTANCE ARE THE RESULT OF TRIVIAL CAUSES

I WOULD RATHER BE FIRST IN A LITTLE IBERIAN VILLAGE THAN SECOND IN ROME

DANGER KNOWS FULL WELL THAT CAESAR IS MORE DANGEROUS THAN HE

        (1)編程思路,

        訊息加密的辦法是:對訊息明文(原文)中的每個字母,分別用該字母之后的第5個字母替換,因此解密時,每個字母,分別用該字母之后的第21(26-5)個字母替換,對于訊息密文字串mess,每個字母解密時,可以用如下運算式簡單完成,

          if(mess[i]>='A'&& mess[i]<='Z')

                mess[i]=(mess[i]-'A'+21)%26+'A';

        (2)源程式,

#include <stdio.h>

#include<string.h>

int main()

{

    char mess[201];

    int i,flag=0;

    while(1)

    {

           gets(mess);

           if(strcmp(mess,"ENDOFINPUT")==0)

                     break;

           if(strcmp(mess,"START")==0)

           {

                     flag = 1;

                     continue;

           }

           if(strcmp(mess,"END")==0)

           {

                     flag=0;

                     continue;

           }

           if(flag==1)

           {

               for(i=0;mess[i]!='\0';i++)

                 if(mess[i]>='A'&& mess[i]<='Z')

                          mess[i]=(mess[i]-'A'+21)%26+'A';

               puts(mess);

           }

     }

    return 0;

}

習題73

73-1  W的密碼

問題描述

加密一條資訊需要三個整數碼:k1, k2 和 k3,字符[a-i] 組成一組,[j-r] 是第二組,其它所有字符([s-z] 和下劃線)組成第三組, 在資訊中屬于每組的字符將被回圈地向左移動ki個位置, 每組中的字符只在自己組中的字符構成的串中移動,解密的程序就是每組中的字符在自己所在的組中回圈地向右移動ki個位置,

例如對于資訊 the_quick_brown_fox 以ki 分別為2,3和1進行加密,加密后變成 _icuo_bfnwhoq_kxert,下圖顯示了右旋解密的程序,

 

觀察在組[a-i]中的字符,我們發現{i,c,b,f,h,e}出現在資訊中的位置為{2,3,7,8,11,17},當k1=2右旋一次后, 上述位置中的字符變成{h,e,i,c,b,f},下表顯示了經過所有第一組字符旋轉得到的中間字串,然后是所有第二組,第三組旋轉的中間字串,在一組中變換字符將不影響其它組中字符的位置,

 

所有輸入字串中只包含小寫字母和下劃線(_),所有字串最多100個字符,ki 是1~100之間的整數,

輸入

輸入包括多組測驗用例,每個測驗用例包括兩行,第1行包括三個整數 k1,k2 和 k3,第2行是待解密的資訊,輸入的最后一行是由三個0組成的,表示輸入結束,

輸出

對于每組加密資料,輸出它加密前的字串,

輸入樣例

2 3 1

_icuo_bfnwhoq_kxert

1 1 1

bcalmkyzx

3 7 4

wcb_mxfep_dorul_eov_qtkrhe_ozany_dgtoh_u_eji

2 4 3

cjvdksaltbmu

0 0 0

輸出樣例

the_quick_brown_fox

abcklmxyz

the_quick_brown_fox_jumped_over_the_lazy_dog

ajsbktcludmv

         (1)編程思路,

        加密時,將密文中的字符分成三組,每組的字符將被回圈地向左移動ki(i=1~3)個位置,這三組各自回圈移位只會移到自己所在組中成員的位置,不會破壞其他組的順序,因此可先求出密文字串中每個組字符的個數、每組中每個字符在明文字串中的下標,最后用mod回圈移位求得明文字串,

        定義陣列int a[105],b[105],c[105];分別保存3個組中各字符在密文字串中的下標,定義int num1,num2,num3;分別保存各組字符的個數,用如下的回圈

               for (i=0;i<strlen(plaintext);i++)

              {

                     if(plaintext[i]>='a'&&plaintext[i]<='i')

                            a[num1++]=i;

                     else if(plaintext[i]>='j'&&plaintext[i]<='r')

                            b[num2++]=i;

                     else

                            c[num3++]=i;

              }

        求出每個組中字符的個數,并保存每個字符在字串中的下標,

        之后,分別用3個回圈對每組進行回圈移位,得到解密后的原文,

       (2)源程式,

#include <stdio.h>

#include <string.h>

int main()

{

       int k1,k2,k3,num1,num2,num3,i;

       int a[105],b[105],c[105];

       char plaintext[105],ciphertext[105];

       while (1)

       {

              scanf("%d%d%d",&k1,&k2,&k3);

              if (k1==0 && k2==0 && k3==0) break;    

              memset(a,-1,sizeof(a));

              memset(b,-1,sizeof(b));

              memset(c,-1,sizeof(c));

              memset(ciphertext,0,sizeof(ciphertext));

              num1=num2=num3=0;

              scanf("%s",plaintext);

              for (i=0;i<strlen(plaintext);i++)

              {

                     if(plaintext[i]>='a'&&plaintext[i]<='i')

                            a[num1++]=i;

                     else if(plaintext[i]>='j'&&plaintext[i]<='r')

                            b[num2++]=i;

                     else

                            c[num3++]=i;

              }

              for (i=0;i<num1;i++)

                     ciphertext[a[(i+k1)%num1]]=plaintext[a[i]];

              for (i=0;i<num2;i++)

                     ciphertext[b[(i+k2)%num2]]=plaintext[b[i]];

              for (i=0;i<num3;i++)

                     ciphertext[c[(i+k3)%num3]]=plaintext[c[i]];

              ciphertext[strlen(plaintext)]='\0';

              printf("%s\n",ciphertext);

       }

    return 0;

}

73-2  古代密碼

問題描述

古羅馬帝國有一個擁有各種部門的強大政府組織,其中一個部門就是保密服務部門,為了保險起見,在省與省之間傳遞的重要檔案中的大寫字母是加密的,當時最流行的加密方法是替換和重新排列,

替換方法是將所有出現的字符替換成其它的字符,有些字符會替換成它自己,例如:替換規則可以是將“A”到“Y”替換成它的下一個字符,將“Z”替換成“A”,如果原詞是 "VICTORIOUS",則它變成 "WJDUPSJPVT",

排列方法改變原來單詞中字母的順序,例如:將順序<2 1 5 4 3 7 6 10 9 8> 應用到 "VICTORIOUS" 上,則得到"IVOTCIRSUO",

人們很快意識到單獨應用替換方法或排列方法加密,都是很不保險的,但是如果結合這兩種方法,在當時就可以得到非常可靠的加密方法,所以,很多重要資訊先使用替換方法加密,再將加密的結果用排列的方法加密,用兩種方法結合就可以將"VICTORIOUS" 加密成"JWPUDJSTVP",

考古學家最近在一個石臺上發現了一些資訊,初看起來它們毫無意義,所以有人設想它們可能是用替換和排列的方法被加密了,人們試著解讀了石臺上的密碼,現在他們想檢查解讀的是否正確,他們需要一個計算機程式來驗證,你的任務就是寫這個驗證程式,

輸入

輸入有兩行,第一行是石臺上的文字,文字中沒有空格,并且只有大寫英文字母,第二行是被解讀出來的加密前的文字,第二行也是由大寫英文字母構成的,

兩行字符數目的長度都不超過100,

輸出

如果第二行經過某種加密方法后可以產生第一行的資訊,輸出 "YES",否則輸出"NO",

輸入樣例

JWPUDJSTVP

VICTORIOUS

輸出樣例

YES

        (1)編程思路,

        定義兩個陣列int a[26]={0},b[26]={0}分別保存輸入兩個字串中各大寫字母出現的次數,例如,a[0]的值是密文字串中字母A出現的次數,b[0] 的值是明文字串中字母A出現的次數,

        由于加密的方法是替換和重新排列,并且明文和密文中只有大寫英文字母,因此,分別求得明文和密文中各大寫字母(A~Z)出現的次數后,將陣列a和b從小到大排列,若兩個陣列對應元素均相等,則輸入的第二行資訊經過某種加密方法后可以產生第一行的資訊;否則,不能,設明文中字母A出現次數最多,加密時字母A被替換為字母E,則加密后字母E的出現次數一定最多,且兩個次數值一定要相等,這樣才可能完成加密,

        (2)源程式,

#include <stdio.h>

void sort(int a[],int n)

{

    int i,j,t;

    for (i=0;i<n-1;i++)

          for (j=0;j<n-1-i;j++)

                 if (a[j]>a[j+1])

                 {

                            t=a[j]; a[j]=a[j+1]; a[j+1]=t;

                 }

}

int main(void)

{

    int a[26]={0},b[26]={0},i;

    char mess1[101],mess2[101];

    scanf("%s%s",mess1,mess2);

    i=0;

    while (mess1[i]!='\0' && mess2[i]!='\0')

    {

        a[mess1[i]-'A']++;

        b[mess2[i]-'A']++;

        i++;

    }

    sort(a,26);

    sort(b,26);

    for(i=0; i<26;i++)

    {

       if(a[i]!=b[i]) break;

    }

    if (i==26)

          printf("YES\n");

    else

          printf("NO\n");

    return 0;

}

73-3  密碼

問題描述

Bob 和 Alice 開始使用一種全新的編碼系統,它是一種基于一組私有鑰匙的,他們選擇了n個不同的數a1,…,an,它們都大于0小于等于n, 加密程序如下:待加密的資訊放置在這組加密鑰匙下,資訊中的字符和密鑰中的數字一一對應起來,資訊中位于i位置的字母將被寫到加密資訊的第ai個位置,ai是位于i位置的密鑰,加密資訊如此反復加密,一共加密 k 次,

資訊長度小于等于n,如果資訊比 n 短, 后面的位置用空格填補直到資訊長度為n,

請你幫助 Alice 和 Bob 寫一個程式,讀入密鑰,然后讀入加密次數 k 和要加密的資訊,按加密規則將資訊加密,

輸入

輸入包括多個測驗用例,每個測驗用例第一行有一個數字n(0 < n <= 200),接下來的行包含n個不同的數字,數字都是大于0小于等于n的,下面每行包含一個k和一個資訊字串,它們之間用空格格開,每行以換行符結束,換行符不是要加密的資訊,每個測驗用例的最后一行只有一個0,最后一個測驗用例只有一行,該行只有一個0,表示輸入結束,無需處理,

輸出

輸出有多個塊,每個塊對應一個測驗用例,每個塊包含輸入中的資訊經過加密后的字串,順序與輸入順序相同,所有加密后的字串的長度都是 n, 每一個塊后有一個空行,

輸入樣例

10

4 5 3 7 2 8 1 6 10 9

1 Hello Bob

1995 CERC

0

0

輸出樣例

BolHeol  b

C RCE

         (1)編程思路,

        加密的方法是進行置換,對于置換可以先求各個回圈節,一個回圈節中的所有字符的置換是不會影響其他字符的,

        以輸入樣例中的資料4 5 3 7 2 8 1 6 10 9為例,可以看出,a[1]=4,a[4]=7,a[7]=1,即(1、4、7)是一個回圈節,a[2]=5,a[5]=2,(2、5)也是一個回圈節,…,(3)、(6、8)、(9、10)是另外的3個回圈節,

        由于給定的加密次數k值可能會很大,因此可以撰寫函式int getm(int a[],int i)求出位置i所在回圈節的長度m,由于回圈節中有m個數,這樣加密m次(置換m次),回圈節中每個數又回到了初始位置,這樣只需加密k%m次即可

       (2)源程式,

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

int getm(int a[],int i)

{

    int ret=1;

    int now=a[i]-1;

    while(now!=i)

    {

        ret++;

        now=a[now]-1;

    }

    return ret;

}

int main()

{

    int key[201];

    char src[201],dest[201];

    int n,i,k,m,kk,now;

    while (scanf("%d",&n) && n!=0)

    {

        for (i=0;i<n;i++)

            scanf("%d",&key[i]);

        while (scanf("%d",&k) && k!=0)

         {

              getchar();

              gets(src);

              for (i=strlen(src);i<n;i++)

                    src[i]=' ';

             src[n]='\0';

             for(i=0;i<n;i++)

              {

                m=getm(key,i);

                kk=k%m;

                now=i;

                while(kk--)

               {

                    now=key[now]-1;

                }

                dest[now]=src[i];

            }

            dest[n]='\0';

            printf("%s\n",dest);

         }

         printf("\n");

    }

    return 0;

}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/438607.html

標籤:C

上一篇:C語言程式設計100例之(72):細菌繁殖

下一篇:C語言程式設計100例之(74):柱狀加密

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more