破译密文

来源:互联网 发布:向json对象里添加元素 编辑:程序博客网 时间:2024/04/29 20:32
【问题描述】
信息的明文是由0和1组成的非空序列。但在网络通信中,为了信息的安全性,常对明文进行加密,用密文进行传输。密文是由0、1和若干个密码字母组成,每个密码字母代表不超过100位不同的01串,例如,密文=011a0bf00a01。密码破译的关键是确定每个密码的含义。
  经过长期统计分析,现在知道了每个密码的固定长度,如今,我方又截获了敌方的两段密文S1和S2,并且知道S1=S2,即两段密文代表相同的明文。你的任务是帮助情报人员对给定的两段密文进行分析,看一看有多少种可能的明文。
【输入格式】
第一行为一个字符串s1
第二行为字符串s2
第三行为整数n,表示有n个小写字母(0<n<=26)
接着n行,每行为一个字符和一个整数,字符的长度
【输出格式】
为一行,为共有多少中明文的可能
【输入样例】
100ad1
cc1
4
a 2
d 3
c 4
b 50
【输出样例】

2

题解和数据, 密码:i7j7,自己做的数据,可能考虑不全勿怪

【问题分析】

此题s1,s2如果全部用二进制的话长度应该是一样的,如果每个字母只代表一个二进制的话就好解决了,只需把s1[i]和s2[i]并在一个集合最后就算有多少个集合再减去根为1的集合和根为0的集合即可,但是这个题的每个变量都是代表多个二进制,那如何解决让一个变量代表一个二进制呢,比如说a代表2个二进制我可以把他写成a1a2,这样a1,和a2各代表一个二进制,那上面样例中的s1可以写成:1 0 0 a1 a2 d1 d2 d3 1,s2可以表示为:c1 c2 c3 c4 c1 c2 c3 c4 1,这样s1[i]与s2[i]就一一对应了。









图片太多,只弄了部分,应该够看,我写代码是因为数据比较小,所以我用a表示为a1,aa表示a2,便于处理

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>using namespace std;struct zm{char ch;int num;};string s1,s2,d[3000];zm a[30];int father[6000];int n,len=0,lend=0,tot=0;void work();int find(int);void merge(int,int);int find_zm(char);int find_k(string);void init();void exchange(string,string b[]);int main(){//freopen("test5.in","r",stdin);//freopen("test1.out","w",stdout);init();work();return 0;}void init(){cin>>s1;cin>>s2;cin>>n;for(int i=1;i<=n;i++){cin>>a[i].ch>>a[i].num;}}void work(){string b[3000],c[3000];exchange(s1,b);//把s1展开存储在b字符串数组 exchange(s2,c);//把s2展开存储在b字符串数组for(int i=1;i<=2*len;i++){father[i]=i;//先初始化,最终的去掉重复的字符串,长度肯定会小于等于2*len }for(int i=1;i<=len;i++){int k1,k2;k1=find_k(b[i]);//查找b[i]在d数组中的位置 k2=find_k(c[i]);//查找c[i]在d数组中的位置if(k1==0)//说明d数组中没有则,加入d数组 {lend++;d[lend]=b[i];k1=lend;}if(k2==0){lend++;d[lend]=c[i];k2=lend;}int f1,f2;f1=find(k1);f2=find(k2);if(f1!=f2)merge(f1,f2);//如果不在一个集合则合并 }for(int i=1;i<=lend;i++){if(father[i]==i && (d[i]!="0"&&d[i]!="1")) tot++;//寻找根节点为非零的集合 }tot=1<<tot;//有几个不确定的集合就有2~tot中可能 cout<<tot<<endl;}int find(int x){if(father[x]==x)return x;father[x]=find(father[x]);return father[x];}void merge(int x,int y){if(d[x]=="1"||d[x]=="0")//合并时如果有1或者0,则一定要让1或0当根 {father[y]=x;return;}father[x]=y;}void exchange(string s,string b[]){len=0;//拆解,比如字母a 长度为3,则拆为3个变量,a,aa,aaa;并存储在b数组里  //其实也可以拆成a1,a2,a3;怎么做自己去实现 for(int i=0;i<s.size();i++){if(s[i]=='1'||s[i]=='0'){ len++; b[len]+=s[i]; continue;}int k=find_zm(s[i]);//找到字符s[i]在字母表中的下标,才能知道a[k].num for(int j=1;j<=a[k].num;j++){len++;b[len].assign(j,a[k].ch);}}}int find_zm(char ch){for(int i=1;i<=n;i++)  if(ch==a[i].ch) return i;return 0;}int find_k(string s){for(int i=1;i<=lend;i++)if(s==d[i])return i;return 0;}


0 0
原创粉丝点击