PC/UVa:110204/843
没想到这道题居然只能穷举。
对于密文的每一个单词,尝试和字典中的每一个单词匹配,如果可以添加没有冲突的映射关系,就继续尝试下一个可以匹配的单词。
如果在添加新的映射关系时,解密表mapDec
或者加密表mapEnc
中出现冲突,就应该把本单词新添加的映射关系去掉,然后就是要注意回溯法要保持递归之前和递归之后状态一致就行了。这道题WA了两次,是因为把vbNew
放在了for
循环外边,并且在恢复状态的时候没有把vbNew
恢复,所以就错了,但是根据uDebug上的结果是测不出来的。
假如把abc
解密为bcd
,但是c
解密为d
时出现了冲突,在没有恢复vbNew
的情况下,ab
仍为新添加的映射关系;当再次把abc
解密为efg
时,此时如果a
解密为e
时发生了冲突,在恢复状态时,因为b
也为新添加的,所以会从解密表中删除b
(但是此时没有添加,mapDec
删除也不会出错),但是在之前可能已经判断f
加密为别的字符了,此时中mapEnc
删除f
的加密关系就会出错了。
#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <set>
#include <vector>
using namespace std;
void decrypt(const set<string> &sstrCipher,
set<string>::iterator sstriterCurr,
map<string, bool> &mstrbDic,
map<char, char>& mccDec, map<char, char>& mccEnc,
map<char, char>& mccTmp, bool &bSolved)
{
if (sstriterCurr == sstrCipher.end()){
//找到了映射
mccDec = mccTmp;
bSolved = true;
return;
}
vector<bool> vbNew(sstriterCurr->size(), false);//新添加的映射关系
for (auto iter = mstrbDic.begin(); iter != mstrbDic.end(); iter++)
{
if (bSolved) return;
//对于字典中每一个没有被映射过的单词
if (!iter->second && iter->first.size() == sstriterCurr->size()){
//判断是否存在重复映射
bool bConflict = false;
for (size_t i = 0; i < sstriterCurr->size(); i++)
{
//解密重复
if (mccTmp.find(sstriterCurr->at(i)) != mccTmp.end()){
if ((mccTmp[sstriterCurr->at(i)] != iter->first.at(i))){
bConflict = true;
break;
}
}
//加密重复
else if (mccEnc.find(iter->first.at(i)) != mccEnc.end()){
if ((mccEnc[iter->first.at(i)] != sstriterCurr->at(i))){
bConflict = true;
break;
}
}
else{
mccTmp[sstriterCurr->at(i)] = iter->first.at(i);
mccEnc[iter->first.at(i)] = sstriterCurr->at(i);
vbNew[i] = true;
}
}
if (bConflict){
for (size_t i = 0; i < sstriterCurr->size(); i++)
{
if (vbNew[i]){
mccTmp.erase(sstriterCurr->at(i));
mccEnc.erase(iter->first.at(i));
vbNew[i] = false;
}
}
continue;
}
//继续映射下一个单词
iter->second = true;
sstriterCurr++;
decrypt(sstrCipher, sstriterCurr, mstrbDic, mccDec, mccEnc, mccTmp, bSolved);
sstriterCurr--;
iter->second = false;
for (size_t i = 0; i < sstriterCurr->size(); i++)
{
if (vbNew[i]){
mccTmp.erase(sstriterCurr->at(i));
mccEnc.erase(iter->first.at(i));
vbNew[i] = false;
}
}
}
}
}
int main()
{
int size = 0;
cin >> size;
string strWord, strCipher;
map<string, bool> mstrbDic;
for (int i = 0; i < size; i++)
{
cin >> strWord;
mstrbDic[strWord] = false;
}
cin.get();
while (getline(cin, strCipher)){
set<string> sstrCipher;
map<char, char> mccDec, mccEnc, mccTmp;
istringstream iss(strCipher);
while (iss >> strWord){
sstrCipher.insert(strWord);
}
bool bSolved = false;
decrypt(sstrCipher, sstrCipher.begin(), mstrbDic, mccDec, mccEnc, mccTmp, bSolved);
for (auto c : strCipher)
{
if (c == ' ') cout << ' ';
else {
if (bSolved) cout << mccDec[c];
else cout << '*';
}
}
cout << endl;
}
return 0;
}
/*
6
and
dick
jane
puff
spot
yertle
bjvg xsb hxsn xsb qymm xsb rqat xsb pnetfn
xxxx yyy zzzz www yyyy aaa bbbb ccc dddddd
*/