110204 Crypt Kicker


#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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值