ACM 1113 - 多个摩尔斯匹配

时间:2015-05-07 13:07:53

标签: c++

我正在尝试解决ACM 1113(http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3554)并且我认为我得到了一个有效的解决方案(至少输出对于我尝试过的多个条目似乎没问题),唯一的问题是我的解决方案被提交系统拒绝了,我不知道为什么因为在我的机器上运行不需要很长时间,有人可以帮助我吗?

/*
 * Multiple morse matches
 */

#include <iostream>
#include <vector>
#include <string>
#include <map>

using namespace std;

std::map<char,string> decodeToMorse;

string toMorse(string w){
    string morse = "";
    for(int i = 0; i < w.size(); i++){
        morse = morse + decodeToMorse[w[i]];        
    }
    return morse;
}

int findPossibleTr( string morse, vector<string> dictMorse, vector<string> dictWords, int index){
    int count = 0;  
    for(int i = 0; i < dictMorse.size(); i++){
        if(morse.compare( index, dictMorse[i].size(), dictMorse[i]) == 0){
            //cout<<"Found " << dictWords[i] << " on index "<<index<<endl;
            if(index+dictMorse[i].size()>=morse.size()){
                //cout<<"Adding one for "<< dictWords[i]<<endl;
                count+=1;
                //return 1;
            }else{
                count += findPossibleTr(morse, dictMorse, dictWords, index+dictMorse[i].size());
            }
        }
    }
    return count;
}


int main(){
    int ncases;
    cin>>ncases;

    decodeToMorse['A'] = ".-";
    decodeToMorse['B'] = "-...";
    decodeToMorse['C'] = "-.-.";
    decodeToMorse['D'] = "-..";
    decodeToMorse['E'] = ".";
    decodeToMorse['F'] = "..-.";
    decodeToMorse['G'] = "--.";
    decodeToMorse['H'] = "....";
    decodeToMorse['I'] = "..";
    decodeToMorse['J'] = ".---";
    decodeToMorse['K'] = "-.-";
    decodeToMorse['L'] = ".-..";
    decodeToMorse['M'] = "--";
    decodeToMorse['N'] = "-.";
    decodeToMorse['O'] = "---";
    decodeToMorse['P'] = ".--.";
    decodeToMorse['Q'] = "--.-";
    decodeToMorse['R'] = ".-.";
    decodeToMorse['S'] = "...";
    decodeToMorse['T'] = "-";
    decodeToMorse['U'] = "..-";
    decodeToMorse['V'] = "...-";
    decodeToMorse['W'] = ".--";
    decodeToMorse['X'] = "-..-";
    decodeToMorse['Y'] = "-.--";
    decodeToMorse['Z'] = "--..";

    for(int i = 0; i < ncases; i++){
        vector<string> dictMorse;
        vector<string> dictWords;
        string morse;
        cin >> morse;
        int ndict;
        cin >> ndict;
        for(int j = 0; j < ndict; j++){
            string dictw;
            cin >> dictw;
            dictMorse.push_back(toMorse(dictw));
            dictWords.push_back(dictw);
        }
        cout<<findPossibleTr(morse,dictMorse, dictWords,0)<<endl;   
        if(ncases != 1 && i != ncases-1)
            cout<<endl; 
    }


}

我尝试了以下输入:

3

.---.-.---...
7
AT
ATC
COS
OS
A
T
C

.---.--.-.-.-.---...-.---.
6
AT
TACK
TICK
ATTACK
DAWN
DUSK

.........
5
E
EE
EEE
EEEE
EEEEE

我得到以下输出(如预期的那样):

5

2

236

唯一的问题是,当我将它提交给裁判系统时,它表示算法花费超过其最大时限(3s)。有什么想法吗?

3 个答案:

答案 0 :(得分:0)

我正在为这种情况写下我的流程,希望它有所帮助。

  1. 我首先会分析算法,看看它是否足够快,可以解决问题。例如,如果n的输入可以大到10 ^ 6且时间限制为1秒,那么O(n2)算法就不会成功。
  2. 然后,将测试输入为“重”&#39;尽可能用于问题陈述(具有最大输入长度或其他的测试用例的最大数量)。如果超过时间限制,代码中可能会有一些内容可以优化以获得较低的常数因子。在经过所有艰难的优化之后,它仍然不够快。在那种情况下,我会回到第1步
  3. 在确定算法没问题之后,我会尝试生成随机输入并尝试几轮,以查看是否存在算法尚未涵盖的任何特殊情况。

答案 1 :(得分:0)

我建议做三件事来改善此代码的性能。

首先,toMorsefindPossibleTr的所有参数都是按值传递的。这将创建一个副本,对于像std::stringstd::vector这样的对象,它将进行内存分配。这将是非常昂贵的,特别是对findPossibleTr的递归调用。要修复它,请更改函数声明以获取const引用,如下所示:

string toMorse(const string& w)
int findPossibleTr( const string& morse, const vector<string>& dictMorse, const vector<string>& dictWords, int index)

其次,toMorse中的字符串连接正在进行分配,并丢弃大量字符串。使用std::stringstream会加快速度:

#include <sstream>
string toMorse(const string& w){
    stringstream morse;
    for(int i = 0; i < w.size(); i++){
        morse << decodeToMorse[w[i]];
    }
    return morse.str();
}

最后,我们可以在vector中重用循环内的main,而不是破坏旧的clear(),并使用// ... vector<string> dictMorse; vector<string> dictWords; for(size_t i = 0; i < ncases; i++){ dictMorse.clear(); dictWords.clear(); string morse; cin >> morse; // ... 每次迭代创建新的。{/ p>

int

将所有这些放在我的机器上使我的速度提高了30%,从测试用例的0.006s到0.004s。还不错。作为奖励,如果您使用的是英特尔平台,Intel's optimization manual表示无符号整数比有符号整数更快,因此我将所有size_t切换为/* * Multiple morse matches * Filipe C */ #include <iostream> #include <vector> #include <string> #include <sstream> #include <map> using namespace std; std::map<char,string> decodeToMorse; string toMorse(const string& w){ stringstream morse; for(size_t i = 0; i < w.size(); i++){ morse << decodeToMorse[w[i]]; } return morse.str(); } size_t findPossibleTr( const string& morse, const vector<string>& dictMorse, const vector<string>& dictWords, size_t index){ size_t count = 0; for(size_t i = 0; i < dictMorse.size(); i++){ if(morse.compare( index, dictMorse[i].size(), dictMorse[i]) == 0){ //cout<<"Found " << dictWords[i] << " on index "<<index<<endl; if(index+dictMorse[i].size()>=morse.size()){ //cout<<"Adding one for "<< dictWords[i]<<endl; count+=1; //return 1; }else{ count += findPossibleTr(morse, dictMorse, dictWords, index+dictMorse[i].size()); } } } return count; } int main(){ size_t ncases; cin>>ncases; decodeToMorse['A'] = ".-"; decodeToMorse['B'] = "-..."; decodeToMorse['C'] = "-.-."; decodeToMorse['D'] = "-.."; decodeToMorse['E'] = "."; decodeToMorse['F'] = "..-."; decodeToMorse['G'] = "--."; decodeToMorse['H'] = "...."; decodeToMorse['I'] = ".."; decodeToMorse['J'] = ".---"; decodeToMorse['K'] = "-.-"; decodeToMorse['L'] = ".-.."; decodeToMorse['M'] = "--"; decodeToMorse['N'] = "-."; decodeToMorse['O'] = "---"; decodeToMorse['P'] = ".--."; decodeToMorse['Q'] = "--.-"; decodeToMorse['R'] = ".-."; decodeToMorse['S'] = "..."; decodeToMorse['T'] = "-"; decodeToMorse['U'] = "..-"; decodeToMorse['V'] = "...-"; decodeToMorse['W'] = ".--"; decodeToMorse['X'] = "-..-"; decodeToMorse['Y'] = "-.--"; decodeToMorse['Z'] = "--.."; vector<string> dictMorse; vector<string> dictWords; for(size_t i = 0; i < ncases; i++){ dictMorse.clear(); dictWords.clear(); string morse; cin >> morse; size_t ndict; cin >> ndict; for(size_t j = 0; j < ndict; j++){ string dictw; cin >> dictw; dictMorse.push_back(toMorse(dictw)); dictWords.push_back(dictw); } cout<<findPossibleTr(morse,dictMorse, dictWords,0)<<endl; if(ncases != 1 && i != ncases-1) cout<<endl; } s,这也修复了一些警告。完整的代码现在变为

:selected

}

答案 2 :(得分:0)

您的算法会耗尽时间,因为它会对字典中与给定摩尔斯电码匹配的所有不同短语执行详尽搜索。它会尝试字典中单词的每一个可能的连接。

虽然这确实给出了正确的答案,但是给定的莫尔斯字符串的长度和字典中的单词数量都需要指数时间。这个问题确实提到了不同短语的数量最多为20亿。

这是一个演示此行为的简单测试用例:

1

... // 1000 dots
2
E
EE

在这种情况下,正确答案将超过10亿,并且必须详尽地搜索所有这些答案。

解决此问题的方法是使用memoizationdynamic programming技术。这里的关键观察是莫尔斯字符串的给定后缀将始终匹配相同数量的不同短语。

附注:在原始代码中,您按值morsedictMorsedictWords传递给了您的回溯功能。这导致在递归函数的每次调用时都复制字符串和两个向量,这是不必要的。您可以通过引用传递,或者(因为这是在竞争性编程环境中可以弯曲良好代码体系结构的指导原则)只是在全局范围内声明它们。我在这里选择了前者:

int findPossibleTr( const string &morse, const vector<string> &dictMorse, const vector<string> &dictWords, vector<int> &memo, int index ) {
    if (memo[index] != -1) return memo[index];

    int count = 0;
    /* ... */
    return memo[index] = count;
}

在你的初始化中:

/* ... */
vector<int> memo(morse.size(), -1); // -1 here is a signal that the values are yet unknown
cout << findPossibleTr(morse, dictMorse, dictWords, memo, 0) << endl;
/* ... */

这几乎立即向上述测试用例吐出答案1318412525

对于每个T测试用例,对于莫尔斯字符串的每个M个后缀,findPossibleTr仅计算一次。每次计算一次考虑N个字中的每一个,比较在字的长度K中取时间线性。通常,这需要O(TMNK)时间,这取决于输入,可能花费太长时间。但是,由于摩尔斯电码中的匹配似乎相对稀疏,因此它应该及时运行。

更复杂的方法是利用数据结构(如trie)来加速字符串匹配过程,总共花费O(TMN)时间。

另一个注意事项:decodeToMorse实际上不一定是map。它可以只是一个数组或26个字符串的vector。对应于字符c的字符串则为decodeToMorse[c - 'A']