2010-08-03 127 views
4

雖然這看起來像Crypt Kicker Problem重複,事實並非如此。Crypt Kicker的更好解決方案?

我已經解決了這個問題,但我不都在一起滿意我的解決方案。這個問題的說法是:

加密文本的共同但有不安全的方法是置換的英文字母。換句話說,字母表中的每個字母在文本中都被其他字母替換。爲確保加密是可逆的,兩個字母不會被同一個字母替換。

你的任務是解密文本的多個編碼行,假設每個行使用不同的一組替代的,並且在解密文的所有單詞都從已知字的字典。

輸入

輸入由含有一個整數n的線,後跟n小寫字,每行一個,按字母順序排列的。這n個單詞組成可能出現在解密文本中的單詞字典。字典後面有幾行輸入。每行都按上面所述加密。

有沒有在字典中超過1000個字。沒有單詞超過16個字母。加密的行只包含小寫字母和空格,長度不超過80個字符。

輸出

解密每個行並打印到標準輸出。如果有多種解決方案,任何人都會這樣做。如果沒有解決方案,請用星號替換字母表中的每個字母。

採樣輸入

迪克

粉撲

yertle

bjvg XSB hxsn XSB qymm XSB rqat XSB pnetfn

XXXX YYY ZZZZ WWW YYYY AAA BBBB CCC DDDDDD

樣本輸出

迪克和簡併抽吸和點和yertle

**** *** **** *** **** *** **** *** ******


我蠻橫逼迫了這個問題:我把字典分成了一個基於長度的集合。然後,我做了一個遞歸蠻力,我試着根據單詞長度嘗試每一個可能的替換,如果沒有匹配,就回溯。它可行,但我對解決方案非常不滿意。我可能只是在迷戀,但似乎應該有一個更優雅的方式來解決這個問題。我的代碼如下:

#include<iostream> 
#include<algorithm> 
#include<vector> 
#include<sstream> 
#include<string> 
#include<map> 
#include<set> 
using namespace std; 
bool Find(vector<set<string > > &dict,vector<string> &line, map<char,char> &dec,int spot){ 
    //Check that the end of the line hasn't been reached 
    if(spot<line.size()){ 
    //Get the size of the current word 
    int sSize=line[spot].size(); 
    string cand; 
    cand.resize(sSize,'A'); 
    //Attempt to decode the current word 
    for(int i=0;i<sSize;i++){ 
     if(dec.find(line[spot][i])!=dec.end()) 
     cand[i]=dec[line[spot][i]]; 
    } 
    //Check all strings in the dictionary of the current length     
    for(set<string>::iterator it=dict[sSize].begin();it!=dict[sSize].end();it++){ 
     bool notMatch=false; 
     for(int i=0;i<sSize;i++) 
     //A is used to signify an undecoded character, this if says if the character was 
     // decoded and it does not equal to corresponding character in the word, it's not     a match 
     if(cand[i]!='A'&&cand[i]!=(*it)[i]) 
     notMatch=true; 
    if(notMatch) 
     continue; 
     for(int i=0;i<sSize;i++) 
     //if it is a feasible match, then add the learned characters to the decoder 
    if(cand[i]=='A') 
     dec.insert(pair<char,char> (line[spot][i],(*it)[i])); 
     //Keep decoding 
     if(Find(dict,line,dec,spot+1)) 
    return true; 
     //If decoding failed, then remove added characters 
     for(int i=0;i<sSize;i++) 
    if(cand[i]=='A') 
     dec.erase(line[spot][i]); 
    } 
    if(spot==0){ 
     //This means no solution was found, fill decoder with a map to astericks 
     string b="qwertyuiopasdfghjklzxcvbnm"; 
     for(int i=0;i<b.size();i++) 
    dec.insert(pair<char,char> (b[i],'*')); 
    } 
    return false; 
    } 
    return true; 
} 
int main(){ 
    int size; 
    cin >> size; 
    vector<set<string> > dict; 
    dict.resize(17); 
    string grab; 
    for(int i=0;i<size;i++){ 
    //Bucket dictionary 
    cin >> grab; 
    dict[grab.size()].insert(grab); 
    } 
    while(getline(cin,grab)){ 
    stringstream in(stringstream::in |stringstream::out); 
    in << grab; 
    vector<string> line; 
    while(in >> grab) 
     line.push_back(grab); 
    map<char,char> dec; 
    Find(dict,line,dec,0); 
    for(int i=0;i<line.size();i++){ 
     for(int j=0;j<line[i].size();j++) 
    cout << dec[line[i][j]]; 
     if(i!=line.size()-1) 
    cout << " "; 
     else 
    cout << endl; 
    } 
    } 
} 

另外,我不是特別感興趣的解決方案,不會在c + +工作。僅僅因爲這是我在編程比賽中使用的語言,所以我只能用它來解決這些問題。我也知道,有不少風格和次要效率的東西,我可以採取不同的做法,而不是太在乎我,我錯過了一兩次休息。主要我只是想知道是否有更簡單的解決方案,或者如果我的實現過於複雜的事情。謝謝。

+1

招呼雅各,你讓你的解決方案接受?我測試了你的,並沒有爲我的輸入工作。 – Clash 2011-04-18 17:58:43

回答

4

我會通過比較單詞中的字母模式來解決這個問題。首先,我會轉換字典,像這樣:

and -> 123 
dick -> 1234 
jane -> 1234 
puff -> 1233 
spot -> 1234 
yertle -> 123452 

這種特殊的字典裏沒有工作也很好,但總的想法是繪製出由字母組成的圖案。例如單詞「字母」映射到1233245,這是一個更好的例子,因爲有多個e和t。

然後我會做同樣的事情,以加密的文本:

bjvg xsb hxsn xsb qymm xsb rqat xsb pnetfn -> 1234 123 1234 123 1233 123 1234 123 123452 

我們可以做一個反向查找並確定第二個字是「和」,五是「噗」和第九是「 yertle」。 「dick」,「jane」和「spot」都有相同的模式,所以我們不能立即告訴他們,但使用從「and」,「puff」和「yertle」獲得的信息可以填補其餘部分。

+0

看來你可以用這種方法修剪搜索空間,通過縮小字典中每個單詞的每個桶。一般而言,這將是有用的,但在問題的範圍內會增加不必要的複雜性。一個好的想法,但。 – JSchlather 2010-08-03 20:29:20

+1

您還可以更智能地選擇開始使用哪個單詞。例如,在您的示例詞典中,您有4個4個字母的單詞,但只有1個3個字母的單詞和1個6個字母的單詞。您的密碼文本以四個字母的單詞開始,但它也包含三個和六個字母的單詞。如果你從這些開始,你會更快地解密文本,因爲你不需要回溯那些文本。這當然需要更多的信息(桶需要按大小排序,並且需要知道密文中每個單詞的長度)。 – 2010-08-03 20:51:41

相關問題