我正在努力解决this problem。 目标是确定莫尔条纹的解释方式,给定一个单词字典。 我所做的是我首先将我的词典中的单词“翻译”成莫尔斯语。然后,我使用了一个朴素的算法,搜索它可以递归解释的所有方法。
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <iterator>
using namespace std;
string morse_string;
int morse_string_size;
map<char, string> morse_table;
unsigned int sol;
void matches(int i, int factor, vector<string> &dictionary) {
int suffix_length = morse_string_size-i;
if (suffix_length <= 0) {
sol += factor;
return;
}
map<int, int> c;
for (vector<string>::iterator it = dictionary.begin() ; it != dictionary.end() ; it++) {
if (((*it).size() <= suffix_length) && (morse_string.substr(i, (*it).size()) == *it)) {
if (c.find((*it).size()) == c.end())
c[(*it).size()] = 0;
else
c[(*it).size()]++;
}
}
for (map<int, int>::iterator it = c.begin() ; it != c.end() ; it++) {
matches(i+it->first, factor*(it->second), dictionary);
}
}
string encode_morse(string s) {
string ret = "";
for (unsigned int i = 0 ; i < s.length() ; ++i) {
ret += morse_table[s[i]];
}
return ret;
}
int main() {
morse_table['A'] = ".-"; morse_table['B'] = "-..."; morse_table['C'] = "-.-."; morse_table['D'] = "-.."; morse_table['E'] = "."; morse_table['F'] = "..-."; morse_table['G'] = "--."; morse_table['H'] = "...."; morse_table['I'] = ".."; morse_table['J'] = ".---"; morse_table['K'] = "-.-"; morse_table['L'] = ".-.."; morse_table['M'] = "--"; morse_table['N'] = "-."; morse_table['O'] = "---"; morse_table['P'] = ".--."; morse_table['Q'] = "--.-"; morse_table['R'] = ".-."; morse_table['S'] = "..."; morse_table['T'] = "-"; morse_table['U'] = "..-"; morse_table['V'] = "...-"; morse_table['W'] = ".--"; morse_table['X'] = "-..-"; morse_table['Y'] = "-.--"; morse_table['Z'] = "--..";
int T, N;
string tmp;
vector<string> dictionary;
cin >> T;
while (T--) {
morse_string = "";
cin >> morse_string;
morse_string_size = morse_string.size();
cin >> N;
for (int j = 0 ; j < N ; j++) {
cin >> tmp;
dictionary.push_back(encode_morse(tmp));
}
sol = 0;
matches(0, 1, dictionary);
cout << sol;
if (T)
cout << endl << endl;
}
return 0;
}
现在问题是我只允许3秒的执行时间,并且我的算法在这个时间限制下无法工作。
这是做这件事的好方法,如果是这样,我错过了什么?否则,你能否给出一些关于什么是好策略的提示?
编辑: 字典中最多可以有10 000个单词,莫尔斯字符串中最多可以有1000个单词。
答案 0 :(得分:0)
将动态编程与rolling hash相结合的解决方案应该适用于此问题。
让我们从一个简单的动态编程解决方案开始。我们分配一个向量,用于存储morse_string
前缀的已知计数。然后我们遍历morse_string
并在每个位置迭代所有单词,我们回头看看它们是否适合morse_string
。如果它们适合,那么我们使用动态编程向量来确定我们可以构建morse_string
前缀到i-dictionaryWord.size()
vector<long>dp;
dp.push_back(1);
for (int i=0;i<morse_string.size();i++) {
long count = 0;
for (int j=1;j<dictionary.size();j++) {
if (dictionary[j].size() > i) continue;
if (dictionary[j] == morse_string.substring(i-dictionary[j].size(),i)) {
count += dp[i-dictionary[j].size()];
}
}
dp.push_back(count);
}
result = dp[morse_code.size()]
这个解决方案的问题是它太慢了。假设N
是morse_string
的长度,M
是dictionary
的大小,K
是字典中最大单词的大小。它将执行O(N*M*K)
次操作。如果我们假设K=1000
这大约是10^10
次操作,这在大多数机器上都太慢了。
K
费用来自dictionary[j] == morse_string.substring(i-dictionary[j].size(),i)
如果我们可以将这个字符串匹配加速到常量或对数复杂度,我们就可以了。这就是滚动哈希的用武之地。如果你构建一个morse_string
的滚动哈希数组,那么你可以计算morse_string
中O(1)
的任何子字符串的哈希值。那么你可以做hash(dictionary[j]) == hash(morse_string.substring(i-dictionary[j].size(),i))
这很好但是在存在不完美的散列的情况下,你可以从字典中使用相同的散列来获得多个单词。这意味着在获得哈希匹配后,您仍然需要匹配字符串以及哈希值。在编程竞赛中,人们通常会假设完美的散列并跳过字符串匹配。这通常是一个安全的赌注,特别是在一本小字典上。如果它不能产生完美的散列(您可以检查代码),您可以随时调整散列函数,并且可能调整的散列函数将产生完美的散列。