// Crypt Kicker (解密)// PC/UVa IDs: 110204/843, Popularity: B, Success rate: low Level: 2// Verdict: Accepted// Submission Date: 2011-05-23// UVa Run Time: 0.536s//// 著作權(C)2011,邱秋。metaphysis # yeah dot net//// 使用遞迴,實際上是回溯的思想來解題相對來說容易一些,演算法是匹配當前的字串,若能匹配,繼續向前// 匹配。#include <iostream>#include <vector>#include <sstream>#include <algorithm>#include <map>using namespace std;bool finished = false;// 提前退出遞迴的標誌。// 將每行輸入拆分為不重複的單詞。bool parse2word(string line, vector < string > &word){istringstream iss(line);string w;bool found;while (iss >> w){found = false;for (int i = 0; i < word.size(); i++)if (w == word[i])found = true;if (!found)word.push_back(w);}return word.size() > 0;}bool cmp(char a, char b){return a < b;}// 檢查是否有兩個密文字母映射到同一明文字母。bool conflicts(string cipher){// 先予以排序,若有相同字母,則排序後肯定相鄰。sort(&cipher[0], &cipher[0] + cipher.length(), cmp);for (int i = 0; i < cipher.length() - 1; i++)if (cipher[i] != '*' && cipher[i + 1] != '*' && cipher[i] == cipher[i + 1])return true;return false;}// 根據當前密碼 cipher,嘗試匹配單詞 d 和 w。bool match(string d, string w, string &cipher){// 儲存當前密碼以便不能匹配時恢複。string tmp = cipher;// 單詞長度不同,肯定無法匹配。if (d.length() != w.length())return false;// 根據明文單詞d和密文單詞 w 逐個字元進行匹配。for (int i = 0; i < w.length(); i++){// 當密文字元 w[i] 尚無對應明文字元匹配時,將密文字元 w[i] 和明文字元 d[i] 匹配。if (cipher[w[i] - 'a'] == '*')cipher[w[i] - 'a'] = d[i];else{// 密文字元 w[i] 已有明文字元匹配,則檢測當前的明文字元 d[i] 是否// 與密碼中的相同,因為不能兩個密文字元對應表同一明文字元,故當兩者不同// 時返回 false。if (cipher[w[i] - 'a'] != d[i]){cipher = tmp;return false;}}}if (conflicts(cipher)){cipher = tmp;return false;}return true;}// 根據擷取的密碼輸出。void output(string line, string cipher){for (int i = 0; i < line.length(); i++)if (line[i] == ' ')cout << ' ';elsecout << cipher[line[i] - 'a'];cout << endl;}// 解密。void decipher(vector < string > &dict, vector < string > &word, int start, string &cipher){// 儲存當前密碼,以便不能匹配時恢複。string tmp = cipher;// 檢測是否已經匹配了所有單詞。if (start == word.size()){// 檢測密碼是否存在衝突。finished = !conflicts(cipher);return;}// 從序號為start的單詞開始匹配。for (int i = 0; i < dict.size(); i++)// 如果能匹配成功單詞 word[start],則匹配單詞 word[start + 1]。if (match(dict[i], word[start], cipher)){// 遞迴向前匹配。decipher(dict, word, start + 1, cipher);// 根據標誌決定是否提前結束遞迴。// 若未匹配到最後一個單詞,恢複密碼為之前儲存的值。if (finished)return;elsecipher = tmp;}}int main(int argc, char *argv[]){string line;int count;vector < string > dict;map < string, int > exist;map < string, int >::iterator it;vector < string > word;cin >> count;cin.ignore();// 讀入單詞字典,注意可能有重複的單詞存在。使用 map 來提高尋找效能。for (int i = 0; i < count; i++){getline(cin, line);it = exist.find(line);if (it == exist.end()){dict.push_back(line);exist.insert(make_pair< string, int >(line, dict.size() - 1));}}// 讀入密文,對每一行進行解碼。while (getline(cin, line)){if (line.length() == 0){cout << endl;continue;}word.clear();parse2word(line, word);finished = false;string cipher(26, '*');if (!(word.size() > dict.size()))decipher(dict, word, 0, cipher);output(line, cipher);}return 0;}