2015年认证杯SPSSPRO杯数学建模B题(第一阶段)替换式密码全过程文档及程序

2015年认证杯SPSSPRO杯数学建模

B题 替换式密码

原题再现:

  历史上有许多密码的编制方法。较为简单的是替换式密码,也就是将文中出现的字符一对一地替换成其它的符号。对拼音文字而言,最简单的形式是单字母替换加密,也就是以每个字母为一个单位,将每个字母替换成另外的字母或者另外的符号。较为复杂的形式是以多个字母为一个单元,整体替换成其它的字符。这个映射方法被称为密码表,拿到密码表的人就能够将密文破译成明文。单字母替换加密是在古代就使用过的一种加密方法,但由于其容易被破解,所以在现代需要加密的场合已经很少使用。
  单字母替换加密的破译方法有频率分析等。这种密码和破译方法在小说中也经常提到,例如爱伦·坡的《金甲虫》和柯南·道尔在福尔摩斯系列故事《归来记》中的“跳舞小人”。但当获取的密文篇幅不是很大时,光凭借频率分析是不足以破译全部密文的。往往还要熟知该种语言的人,经过对可能出现的词汇及字母组合进行分析,才能完整地破译密码。
  第一阶段问题: 假设明文是由现代通常使用的英语写成的。现在我们获取了一些由单字母加密方法加密的密文。请你建立合理的数学模型,设计一个算法,来自动化地破译密文。并设计一个衡量破译能力的标准,来评价破译算法的破译能力。为了问题简单起见,我们假设密码表仅是针对 26 个字母的,每个单词之间的空格,以及标点符号仍然会保留。在设计算法时,如果需要,可以参考英文语料库的数据,例如免费的 COCA1等相关资料。

整体求解过程概述(摘要)

  单字母替换式密码的研究对密码破解有很大的影响,本文研究了简单的单字母替换式密码破译的问题,建立了离散优化模型,首先设计了穷举算法、频率分析算法、字典树 dfs 算法。
  对于穷举算法,从所有可能的对应关系中随机选出一种,然后判断其是否为密钥,若是其是所求密钥则得出明文,否则选取其他规则进行进行判断,本文从运算复杂度等因素对该算法进行分析。
  对于频率分析算法,根据单字母高频统计表,按照英文构词与语法的统计规则入手,按照明文和密文字母出现频率进行分析,得到频率分析算法解密的正确率为 80%。
  对于字典树 dfs 算法,首先利用字典库中的单词构建一棵字典树,在深度优先搜索的同时记录当前搜索确定的单词前缀在字典树中对应的结点,利用该结点新加某字母 x的不可到达字典树已构建好的任一结点的性质,及时剪枝——不再搜索密文下一位字母解密后为某字母 x 的可能性。通过程序测试,当密文篇幅大于 100 单词时,可直接生成结果;当篇幅介于 40-100 时,可生成两个左右的结果,可通过人为直接判别出结果;当密文由不到十个词汇组成时,则根据密文所符合的构词规则会生成几个到几百个不定的结果,此时想要得出合适的明文需要依靠人力完成。然后本文将三种算法通过对不同类型的密文进行对比,得到频率分析算法适合大篇幅的密文,字典树剪枝算法不仅适合求出大篇幅的密文,也可以通过加上少量人工的判断可以求出较短篇幅的密文。
  最后,本文假设结合频率分析算法与字典树 dfs 算法,预测对于短篇幅的密文的人工判别的次数将大量减少。

问题分析:

  本题是研究单字母替换密码问题,替换规则多种多样,较为常见的如凯撒密码,仿射密码,摩斯密码等,但常见的替换规则均有特殊性,不能代表普遍的替换规则。我们在本题中以随机单字母替换规则建立数学模型,设计算法,并进一步求解。
  对于篇幅很大的密文,我们可以用频率分析的方法,根据密文中字母的频率分布推测加密规则。但是当获取的密文篇幅不是很大时,光凭借频率分析是不足以破译全部密文的。往往要经过对可能出现的词汇及字母组合进行分析判断,才能完整地破译密文。单字母替换规则是随机的,一共有 26!种情况,对于随机替换情况需要做一步一步的优化,使得选取随机的方式更为简单,从而达到大大减少运算量的目的。
  对于上述建立模型的方法,在设计算法求解过程中,难以避免的是 26 个字母中有少量字母的替换规则出错,尤其是密文篇幅少且单词长度短,构成正确单词的解有多个,导致明文的正确度降低。于是,我们需要对所建立的几个模型进行对比,根据不同算法的不同适用范围对解密方法进行破译能力划分。
  此外,本题是个实际问题,现实中需要考虑的因素远远多于题目本身,如何使模型更加贴近实际,并提供有效的单词数据库是本文面临的一大困难,通过查阅大量资料与文献,并进行适当的、合理的假设,对单字母替换密码的解密方式进行研究。

模型假设:

  模型假设
  假设一:根据题目要求,假设我们得到的密文所用的加密密码表仅针对 26 个字母进行加密,空格与标点仍然保留。
  假设二:设计算法时,假设被加密的明文中并没有(或者数量极少)专有名词和奇怪拼写。
  假设三:密文没有时效性(即在设计算法时并不考虑运行时间)。
  假设说明
  对于假设一属于题目要求,为简化算法而存在。
  对于假设二、三是为设计算法而提出的,我们可以将其视作密文的一般情况,实际上,假设二、三也符合多数密文的实际状况。对于二三的特殊情况,需要根据实际情况更改单词库和部分规则。

论文缩略图:

在这里插入图片描述
在这里插入图片描述

全部论文请见下方“ 只会建模 QQ名片” 点击QQ名片即可

部分程序代码:(代码和文档not free)

1 //下文中替换规则 a->b 均指在加密过程中 a 被替换成 b
2 #include <cstdio>
3 #include <cstring>
4 #include <algorithm>
5 #include <cstdlib>
6 using namespace std;
7 char s[100];
8 FILE *f1;
9 FILE *f2;
10 FILE *f3;
11 #define MAXWN 100000 //密文中单词个数的上限
12 struct node
13 {
14 char lex[30]; //单个单词长度最大为 30
15 int lenn; //该单词的长度
16 int id; //该单词在密文中是第几个出现的
17 int punc; //为 1 表示是标点符号,为 0 表示是单词
18 bool operator<(const node&oth)const//将单词按长度从大到小排序
19 {
20 if (lenn!=oth.lenn) return lenn>oth.lenn;
21 if (strcmp(lex,oth.lex)>0) return 1;
22 else return 0;
23 }
24 } a[MAXWN]; //存密文中单词的数组
25
26 int F[MAXWN];//F[i]存密文中第 i 个单词在从大到小排序后位于第 F[i]个位置,排序后得到,解密
输出密文时用到
27
28 int word_num;//密文中单词总数,由实际从密文文件读入确定
29 int dictionary_num;//字典中单词总数,由实际从字典文件读入确定
30
31 #define MAXTN 1000000//字典树中结点总个数的上限
32 int f[MAXTN][26];//f[i][j]表示若在编号为 i 的结点,再经过一个字母 j,到达的结点的编号
33 int v[MAXTN]; //v[i]=1 表示从根结点出发停留在字典树编号为 i 的结点,顺次经过的字母组
成的单词在之前的字典里
34 int tree_num; //字典树中结点总个数,主要在构建字典树时用到
35 void add(char *s)
36 {
37 int len=strlen(s);
38 int tmp=0; //一开始停留在编号为 0 的根节点
39 for (int i=0; i<len; i++)
40 {
41 if (f[tmp][s[i]-'a']==-1) //如果从 tmp 出发经过字母 s[i]到达的结点还没有新建
42 f[tmp][s[i]-'a']=++tree_num; //新建之,编号为++tree_num
43 tmp=f[tmp][s[i]-'a'];//经过一个字母 s[i],tmp 编号的改变
44 
45 v[tmp]=1; //最后停留在编号为 tmp 是一个字典里的单词
46 }
47 int vis[26];//若有加密规则 a->b(0<=a<26,0<=b<26),则 vis[a]=b;vis[a]==-1 表示 a->?(a 被替换成什
么字母当前未知)
48 int ans[26];//若有加密规则 a->b(0<=a<26,0<=b<26),则 ans[b]=a;ans[b]==-1 表示->b(什么字母被替
换成 b 当前未知)
49 int startx,endx;//当前指定的要求解密的单词为从 a[beginx,endx]里所有单词
50 int successful_sol;//成功的方案数
51
52 void print_solution()
53 {
54 fprintf(f3,"=============sol:%d===============\n",successful_sol);
55 /*如果有替换规则 a->b,b->c,c->a,……
56 会输出 a b c
57 | | |
58 v v v
59 b c a
60 */
61 for (int i=0; i<26; i++)
62 fprintf(f3,"%c ",i+'a');
63 fprintf(f3,"\n");
64 for (int i=0; i<26; i++)
65 fprintf(f3,"| ");
66 fprintf(f3,"\n");
67 for (int i=0; i<26; i++)
68 fprintf(f3,"v ");
69 fprintf(f3,"\n");
70 for (int i=0; i<26; i++)
71 if (vis[i]==-1)fprintf(f3,"? ");
72 else fprintf(f3,"%c ",vis[i]);
73 fprintf(f3,"\n\n");
74
75 for (int i=0; i<word_num; i++)
76 {
77 if (a[F[i]].punc==1) //如果是标点符号直接输出标点符号
78 fprintf(f3,"%s",a[F[i]].lex);
79 else //否则对每个字母解密后输出
80 {
81 if (i>0&&a[F[i-1]].punc==0)
82 fprintf(f3," ");
83 for (int j=0; j<a[F[i]].lenn; j++)
84 fprintf(f3,"%c",ans[a[F[i]].lex[j]-'a']+'a');
85 }
86 }
87 fprintf(f3,"\n\n");
88 }
89 void dfs(int x,int y,int tmp)
90 //当前已解密到从第 x 的单词的第 y 位,第 x 个单词解密后停留在字典树的第 tmp 号结点
91 {
92 if (x==endx+1) //第 endx 个单词也解密完成,能找到一种替换规则解密所有被指定的
单词
93 {
94 successful_sol++;
95 print_solution();
96 return;
97 }
98 if (a[x].punc==1)
99 {
100 dfs(x+1,0,0);
101 return;
102 }
103 if (a[x].lenn==y) //解密到第 x 个单词的第 len(x)位,即已知道第 x 个单词各字母由什么字
母加密而来
104 {
105 if (v[tmp]) //如果按这种规则解密后的第 x 个单词是字典中的单词
106 dfs(x+1,0,0); //从第 x+1 个单词的第 0 位开始解密,停留在字典树的 0 号根节点
107 return;
108 }
109 for (int i=0; i<26; i++) //枚举?->单词 x 的第 y 位
110 if (f[tmp][i]!=-1) //强力剪枝
111 //如果单词 x 的前 y-1 位加上 i 构不成任何单词的前缀,则不可能由 i->单词 x 的第
y 位
112 {
113 if (vis[i]==-1&&ans[a[x].lex[y]-'a']==-1)
114 //i->? 并且 ?->单词 x 的第 y 位
115 {
116 vis[i]=a[x].lex[y];
117 ans[a[x].lex[y]-'a']=i; //修改 vis 和 ans
118 dfs(x,y+1,f[tmp][i]); //从第 x 个单词的 y+1 位开始解
密,当前停留结点编号做相应改变
119 vis[i]=-1;
120 ans[a[x].lex[y]-'a']=-1; //还原 vis 和 ans
121 }
122 else if (vis[i]==a[x].lex[y]) //之前就已知 i->单词 x 的第 y 位,与当前枚举 i->单词 x
的第 y 位不冲突
123 {
124 dfs(x,y+1,f[tmp][i]);
125 }
126 }
127 }
128 //-------------------------------------------
129 int left=0,nlen=0;
130 void addword()
131 {
132 s[nlen++]='\0';
133 strcpy(a[word_num].lex,s);
134 a[word_num].lenn=strlen(a[word_num].lex);
135 a[word_num].id=word_num; //在未排序之前,第 i 个产生的单词在密文中的位置为
第 i 个
136 a[word_num].punc=(left==1?1:0);
137 word_num++;
138 left=0;
139 nlen=0;
140 }
141 void read_passage()//从密文文件中读入所有以空白字符隔开的字符串,处理掉标点符号后以单词
形式存入 a 数组
142 {
143 word_num=0;
144 char cc;
145 while (fscanf(f2,"%c",&cc)!=EOF)
146 {
147 if (cc==' '||cc=='\t'||cc=='\n')
148 {
149 if (left==1)s[nlen++]=' ';
150 if (left)addword();
151 }
152 else if (cc>='a'&&cc<='z'||cc>='A'&&cc<='Z')
153 {
154 if (left==1)addword();
155 if (cc<='Z')cc+=32;
156 if (left==0)left=2;
157 s[nlen++]=cc;
158 }
159 else
160 {
161 if (left)addword();
162 if (left==0)left=1;
163 s[nlen++]=cc;
164 }
165 }
166 if (left)addword();
167
168
169 sort(a,a+word_num);
170 for (int i=0; i<word_num; i++)
171 F[a[i].id]=i; //得到 F 数组
172 }
173 //-------------------------------------------
174 void create_trie()
175 {
176
177 memset(f,255,sizeof(f)); //字典树初始化
178 memset(v,0,sizeof(v)); //字典树初始化
179 tree_num=0; //字典树初始化
180
181 //从字典文件读入所有的单词,并构建一棵字典树
182 dictionary_num=0;
183 while (fscanf(f1,"%s",s)!=EOF)
184 {
185 add(s);
186 dictionary_num++;
187 }
188 }
189 int main()
190 {
191 int size = 128 << 20; //G++扩栈语句
192 char *p = (char*)malloc(size) + size; //G++扩栈语句
193 __asm__("movl %0, %%esp\n" :: "r"(p));//G++扩栈语句
194 //如果编译器是 C++,应该注释掉上面三句,并在这个程序#include <cstdio>前加一句
195 //#pragma comment(linker, "/STACK:102400000,102400000")
196 f1=fopen("dic1.txt","r"); //只读方式打开字典文件
197 f2=fopen("text2.txt","r"); //只读方式打开密文文件
198 f3=fopen("ans.txt","w");//只写方式打开解密文文件
199
200 create_trie();
201 read_passage();
202
203 printf("dic=%d word=%d tree=%d\n",dictionary_num,word_num,tree_num);//调试语句
204
205 memset(vis,255,sizeof(vis));
206 memset(ans,255,sizeof(ans));
207 startx=0;
208 endx=word_num-1;
209 dfs(startx,0,0);
210 printf("%d\n",successful_sol);
211 system("pause");
212 }
213
214
全部论文及程序请见下方“ 只会建模 QQ名片” 点击QQ名片即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/287433.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小迪安全48WEB 攻防-通用漏洞Py 反序列化链构造自动审计 bandit魔术方法

#知识点&#xff1a; 1、Python-反序列化函数使用 2、Python-反序列化魔术方法 3、Python-反序列化 POP 链构造&#xff08;payload构造&#xff09; 4、Python-自动化审计 bandit 使用 #前置知识&#xff1a; 函数使用&#xff1a; pickle.dump(obj, file) : 将对…

pycharm使用远程服务器的jupyter环境

1、确保服务器上安装了jupyter,如果没有&#xff0c;执行下面命令安装 pip install jupyter2、启动jupyter notebook服务 jupyter notebook --no-browser --port8888 --ip0.0.0.0 --allow-root表明在服务器的8888 端口上启动 Jupyter Notebook&#xff0c;并允许从任何 IP 地…

caffe | 使用caffe SSD制作VOC07112 lmdb数据集

git clone -b ssd https://github.com/weiliu89/caffe.git caffe_ssdcd caffe_ssdcp caffe/Makefile.config caffe_ssd/# 把 cuda 和 cudnn 关了&#xff0c;用 cpu 版本的就好了 make -j32 make pycaffemake test -j8 make runtest -j8 vim ~/.bashrc# 加入 export LD_LIBRAR…

亮数据代理IP轻松解决爬虫数据采集痛点

文章目录 一、爬虫数据采集痛点二、为什么使用代理IP可以解决&#xff1f;2.1 爬虫和代理IP的关系2.2 使用代理IP的好处 三、亮数据代理IP的优势3.1 IP种类丰富3.1.1 动态住宅代理IP3.1.2 静态住宅代理IP3.1.3 机房代理IP3.1.4 移动代理IP 3.2 高质量IP全球覆盖3.3 超级代理服务…

达梦DEM部署说明-详细步骤-DM8达梦数据库

DMDEM部署说明-详细步骤-DM8达梦数据库 环境介绍1 部署DM8 数据库 1.1 创建一个数据库作为DEM后台数据库1.2 创建数据库用户 DEM1.3 使用DEM用户导入dem_init.sql 2 配置tomcat 2.1 配置/tomcat/conf/server.xml2.2 修改jvm启动参数 3 配置JAVA 1.8及以上版本的运行时环境 3.1…

线性数据结构----(数组,链表,栈,队列,哈希表)

线性数据结构 数组链表栈使用场景 队列应用场景 哈希表特点哈希函数&#xff0c;哈希值&#xff0c;哈希冲突键值对 Entry 开放寻址法和拉链法 参考文档 数组 数组(Array) 是一种很常见的数据结构。由相同类型的元素组成&#xff0c;并且是使用一块连续的内存来存储的。 在数组…

【二】TensorFlow神经网络模型构建之卷积函数

卷积函数是构建神经网络的重要支架&#xff0c;是在一批图像上扫描的二维过滤器。 tf.nn.convolution(input,filter,padding,stridesNone,dilation_rateNone,nameNone,data_formatNone)该函数计算N维卷积的和。tf.nn.conv2d(input,filter,padding,strides,use_cudnn_on_gpuNon…

java算法第31天 | 贪心算法 part01 ● 理论基础 ● 455.分发饼干 ● 376. 摆动序列 ● 53. 最大子序和

理论基础 贪心算法没有固定的套路&#xff0c;贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 贪心算法一般分为如下四步&#xff1a; 将问题分解为若干个子问题 找出适合的贪心策略 求解每一个子问题的最优解 将局部最优解堆叠成全局最优解 这个四步其…

分布式系统面试全集通第一篇(dubbo+redis+zookeeper----分布式+CAP+BASE+分布式事务+分布式锁)

目录 分布式系统面试全集通第一篇什么是分布式?和微服务的区别什么是分布式分布式与微服务的区别 什么是CAP?为什么不能三者同时拥有分区容错性一致性可用性 Base理论了解吗基本可用软状态最终一致性 什么是分布式事务分布式事务有哪些常见的实现方案?2PC&#xff08;Two Ph…

如何查询电脑是否被锁定了IP地址?锁定IP会出现什么问题?

前言 电脑刚到手的时候&#xff0c;基本上是通过路由器DHCP进行IP分配的。路由器DHCP分配IP给电脑的好处是网络不会出现IP冲突&#xff0c;网络能正常使用。 有些电脑可能在DHCP自动获取IP时出现错误&#xff0c;所以小伙伴就会通过手动设置IP让电脑可以正常上网。 这样的操…

3-iperf3 使用什么工具可以检测网络带宽、延迟和数据包丢失率等网络性能参数呢?

(1)iperf3简介 1.iperf3简介 2.用途&#xff08;特点&#xff09; 3.下载iperf3地址 &#xff08;2&#xff09;实战 1.iperf3参数 &#xff08;1&#xff09;通用参数&#xff08;客户端和服务器端都是适用的&#xff09; &#xff08;2&#xff09;客户端参数 实验1&…

35.基于SpringBoot + Vue实现的前后端分离-在线考试系统(项目 + 论文)

项目介绍 本站是一个B/S模式系统&#xff0c;采用SpringBoot Vue框架&#xff0c;MYSQL数据库设计开发&#xff0c;充分保证系统的稳定性。系统具有界面清晰、操作简单&#xff0c;功能齐全的特点&#xff0c;使得基于SpringBoot Vue技术的在线考试系统设计与实现管理工作系统…

RN封装的底部向上弹出的弹出层组件

组件代码 import React from react; import { View, StyleSheet, Modal, TouchableOpacity, Text, TouchableWithoutFeedback } from react-native;const BottomPopup ({ visible, onClose, children, leftButtonTitle, rightButtonTitle, onLeftButtonPress, onRightButtonP…

【分布式】——降级熔断限流

降级&熔断&限流 ⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记仓库&#x1f449;https://github.com/A-BigTree/tree-learning-notes 个人主页&#x1f449;https://www.abigtree.top ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点…

雷卯推荐多种系列汽车级TVS供您选择

1. 车规级TVS的应用 2.车规级TVS系列表格如下 3.方案推荐 12V汽车电源浪涌保护方案 方案优点&#xff1a;用于满足前装汽车的ISO7637-2 5A5BA测试&#xff0c;可采用单独大功率的TVS或PTCTVS的组合方案&#xff0c;满足ISO10605-2&#xff0c; 等级4&#xff0c;接触放电15K…

HWOD:句子逆序

一、题目 描述 将一个英文语句以单词为单位逆序排放。例如I am a boy逆序排放后为boy a am I。所有单词之间用一个空格隔开。语句中除了英文字母外&#xff0c;不再包含其他字符。 数据范围 输入的字符串长度满足 1<n<1000 输入 输入一个英文语句&#xff0c;每个…

从零开始搭建游戏服务器 第七节 创建GameServer

目录 前言正文创建GameServer模块修改配置创建NettyClient连接到登录服登录服修改创建协议游戏服注册到登录服 总结 前言 上一节我们使用自定义注解反射简化了协议解包和逻辑处理分发流程。 那么到了这里登录服登录服的架构已经搭建的差不多了&#xff0c;一些比较简单的、并发…

elementui的table根据是否符合需求合并列

<el-table :data"tableData" border style"width: 100%;" :span-method"objectSpanMethodAuto"><!-- 空状态 --><template slot"empty"><div><img src"/assets/images/noData.png" /></di…

【多模态融合】SuperFusion 激光雷达与相机多层次融合 远距离高清地图预测 ICRA 2024

前言 本文介绍激光雷达与相机进行多层次融合&#xff0c;包括数据级融合、特征级融合和BEV级融合。 融合后的BEV特征可以支持不同的任务头&#xff0c;包括语义分割、实例编码和方向预测&#xff0c;最后进行后处理生成高清地图预测&#xff0c;它是来自ICRA 2024的。 会讲解…

【Java并发知识总结 | 第五篇】深入理解Synchronized底层原理(Monitor对象、Synchronized锁优化)

文章目录 5.深入理解Synchronized底层原理&#xff08;Monitor对象、Synchronized锁优化&#xff09;5.1Synchronized的特性5.1.1原子性5.1.2可见性5.1.3有序性5.1.4可重入性 5.2Synchronized的用法5.3Synchronized的两种同步方式4.3.1同步代码块5.3.2同步方法 5.4Synchronized…