#include <stdio.h>
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <string.h>
using namespace std;
#define MAX_WORD_LEN 16
#define MAX_BUF_SIZE 4096
typedef vector<string*> DictStrCol_t;
typedef vector<char*> LineStrCol_t;
typedef map<char, char> RulesSet_t;
class Dict
{
public:
~Dict()
{
for (int i = 1; i <= MAX_WORD_LEN; ++i)
{
ClearStrCol(m_Words[i]);
}
}
void AddStr(char* str)
{
m_Words[strlen(str)].push_back(new string(str));
}
const DictStrCol_t* GetCandidateDictStrs(int nLen) const
{
if ((nLen < 1) || (nLen > MAX_WORD_LEN))
return NULL;
return &(m_Words[nLen]);
}
private:
static void ClearStrCol(DictStrCol_t& strCol)
{
DictStrCol_t::iterator strIter = strCol.begin();
for(int j = 0; j < strCol.size(); ++j)
delete (*(strIter + j));
strCol.clear();
}
private:
DictStrCol_t m_Words[MAX_WORD_LEN + 1];
};
enum AddRuleResult_t
{
CAN_ADD = 0,
CONFLICT_WITH_EXIST,
EXISTED
};
enum ParseResult_t
{
SUCCESS = 0,
FAIL,
ABORT
};
class MapRules
{
public:
MapRules()
{
for (char x = 'a'; x <= 'z'; ++x)
{
m_Rules[x - 'a'] = '*';
m_InvertRules[x - 'a'] = '*';
}
}
char GetDecryptedChar(char encryptedChar) const
{
return m_Rules[encryptedChar - 'a'];
}
void AddRules(const RulesSet_t* pNewRules)
{
if (!pNewRules)
return;
RulesSet_t::const_iterator iter = pNewRules->begin();
while(iter != pNewRules->end())
{
m_Rules[iter->first - 'a'] = iter->second;
m_InvertRules[iter->second - 'a'] = iter->first;
++iter;
}
}
void RemoveRules(const RulesSet_t* pToDeleteRules)
{
if (!pToDeleteRules)
return;
RulesSet_t::const_iterator iter = pToDeleteRules->begin();
while(iter != pToDeleteRules->end())
{
char curValue = m_Rules[iter->first - 'a'];
m_Rules[iter->first - 'a'] = '*';
m_InvertRules[curValue - 'a'] = '*';
++iter;
}
}
AddRuleResult_t CanAddRule(char encryptedChar, char decryptedChar) const
{
char curValue = m_Rules[encryptedChar - 'a'];
char curInvertValue = m_InvertRules[decryptedChar - 'a'];
if (('*' == curValue) && ('*' == curInvertValue))
return CAN_ADD;
if ((curValue == decryptedChar) && (curInvertValue == encryptedChar))
return EXISTED;
return CONFLICT_WITH_EXIST;
}
private:
char m_Rules[26];
char m_InvertRules[26]; // Help to make sure that no two letters can be mapped to a same letter.
};
class CandidateRules
{
public:
enum RulesInitResult_t
{
INIT_OK = 0,
NONE_IN_DICT,
INIT_FAIL
};
~CandidateRules()
{
int nCnt = GetCnt();
for (int i = 0; i < nCnt; ++i)
{
delete m_Rules[i];
delete m_InvertRules[i];
}
}
RulesInitResult_t Init(const Dict& dict, const MapRules& existingRules, char* str)
{
int nLen = strlen(str);
const DictStrCol_t* dictWords = dict.GetCandidateDictStrs(nLen);
if ((!dictWords) || (dictWords->size() <= 0))
return NONE_IN_DICT;
bool isSuccessful;
RulesSet_t *newRules, *invertRules;
for (int i = 0; i < dictWords->size(); ++i)
{
if (GetNewRules((*(dictWords->begin() + i))->c_str(), str, nLen, existingRules, &newRules, &invertRules))
{
m_Rules.push_back(newRules);
m_InvertRules.push_back(invertRules);
}
}
return (m_Rules.size() > 0) ? INIT_OK : INIT_FAIL;
}
int GetCnt()
{
return m_Rules.size();
}
RulesSet_t* GetRule(int nIndex)
{
return m_Rules[nIndex];
}
private:
AddRuleResult_t CanAddRule(char dictLetter, char strLetter, const MapRules& existingRules, RulesSet_t* newRules, RulesSet_t* invertRules)
{
AddRuleResult_t result = existingRules.CanAddRule(strLetter, dictLetter);
if ((CONFLICT_WITH_EXIST == result) || (EXISTED == result))
return result;
int existingEncrptedLetterCnt = newRules->count(strLetter);
int existingDecrptedLetterCnt = invertRules->count(dictLetter);
if ((existingEncrptedLetterCnt <= 0) && (existingDecrptedLetterCnt <= 0))
return CAN_ADD;
if ((existingEncrptedLetterCnt == 1) && (existingDecrptedLetterCnt == 1))
{
if ((newRules->operator[](strLetter) == dictLetter) &&
(invertRules->operator[](dictLetter) == strLetter))
return EXISTED;
}
return CONFLICT_WITH_EXIST;
}
bool GetNewRules(
const char* dictWord, char* str, int nLen, const MapRules& existingRules,
RulesSet_t** pNewRules, RulesSet_t** pInvertRules)
{
*pNewRules = new RulesSet_t();
*pInvertRules = new RulesSet_t();
for(int i = 0; i < nLen; ++i)
{
AddRuleResult_t result = CanAddRule(dictWord[i], str[i], existingRules, *pNewRules, *pInvertRules);
if (CONFLICT_WITH_EXIST == result)
{
delete (*pNewRules);
*pNewRules = NULL;
delete (*pInvertRules);
*pInvertRules = NULL;
return false;
}
if (CAN_ADD == result)
{
(*pNewRules)->insert(pair<char, char>(str[i], dictWord[i]));
(*pInvertRules)->insert(pair<char, char>(dictWord[i], str[i]));
}
}
return true;
}
private:
vector<RulesSet_t*> m_Rules;
vector<RulesSet_t*> m_InvertRules; // Help to make sure that no two letters can be mapped to a same letter.
};
void GetWordsFromLine(char* pLine, LineStrCol_t& strCol)
{
int start = 0;
int nIndex = 0;
while(pLine[nIndex] != '\0')
{
if ((pLine[nIndex] == ' ') || (pLine[nIndex] == '\n'))
{
pLine[nIndex] = '\0';
strCol.push_back(pLine + start);
++nIndex;
start = nIndex;
continue;
}
++nIndex;
}
}
void OutputDecryptedLine(LineStrCol_t& lineStrCol, MapRules& rules)
{
int nWordsCnt = lineStrCol.size();
for (int i = 0; i < nWordsCnt; ++i)
{
char* ptr = lineStrCol[i];
while((*ptr) != '\0')
{
*ptr = rules.GetDecryptedChar(*ptr);
++ptr;
}
cout << lineStrCol[i];
if (i < nWordsCnt - 1)
cout << ' ';
else
cout << endl;
}
}
ParseResult_t GetRules(Dict& dict, const LineStrCol_t& encrptedWords, int curIndex, MapRules& rules)
{
if (curIndex >= encrptedWords.size())
return SUCCESS;
CandidateRules candidateNewRules;
CandidateRules::RulesInitResult_t initResult = candidateNewRules.Init(dict, rules, encrptedWords[curIndex]);
if (CandidateRules::NONE_IN_DICT == initResult)
return ABORT;
if (CandidateRules::INIT_OK != initResult)
return FAIL;
int nCnt = candidateNewRules.GetCnt();
if (nCnt <= 0)
return FAIL;
for(int i = 0; i < nCnt; ++i)
{
RulesSet_t* newRules = candidateNewRules.GetRule(i);
rules.AddRules(newRules);
ParseResult_t result = GetRules(dict, encrptedWords, curIndex+1, rules);
if (SUCCESS == result)
return SUCCESS;
rules.RemoveRules(newRules);
if (ABORT == result)
return ABORT;
}
return FAIL;
}
void DecryptLine(Dict& dict, char* pLine)
{
int nLen = strlen(pLine);
LineStrCol_t encryptedWords;
GetWordsFromLine(pLine, encryptedWords);
MapRules rules;
GetRules(dict, encryptedWords, 0, rules);
OutputDecryptedLine(encryptedWords, rules);
}
void DoWork(Dict& dict)
{
int nDictWordsCnt = 0;
cin >> nDictWordsCnt;
char buf[MAX_BUF_SIZE];
for(int i = 0; i < nDictWordsCnt; ++i)
{
cin >> buf;
dict.AddStr(buf);
}
fgets(buf, MAX_BUF_SIZE, stdin); // Consume the "\n" after the last word in dictionary.
while(true)
{
char* ptr = fgets(buf, MAX_BUF_SIZE, stdin);
if (!ptr)
return;
if (buf[0] == '\n')
{
cout << endl;
continue;
}
DecryptLine(dict, buf);
}
}
int main(int argc, char* argv[])
{
Dict dict;
DoWork(dict);
return 0;
}