现在的位置: 首页 > 综合 > 正文

破译密文

2018年01月17日 ⁄ 综合 ⁄ 共 2367字 ⁄ 字号 评论关闭

【问题描述】
信息的明文是由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;
}

【上篇】
【下篇】

抱歉!评论已关闭.