破譯密文

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章