习题4-6 UVA508 Morse Mismatches(38行AC代码)

紫书刷题进行中,题解系列点这里

习题4-6 UVA508 Morse Mismatches(38行AC代码)

思路分析

已知字符编码表,接受的单词表(context),现给出摩尔斯电码,根据规则解码。规则如下:

  • 1个精确匹配:直接输出
  • 多个精确匹配:输出字典序最小/context中最前面的都对(原题描述有些歧义fewest character长度最短?)
  • 0个精确匹配:找出最小模糊匹配,即两个字符串存在这样的关系:a是b的子串/b是a的子串,且二者长度相差最小(若有多个满足,输出任意单词即可)

算法设计

  • 惯性思维:想直接从摩尔斯密码来解码,那么必须dfs许多情况,过于复杂。

  • 逆向思维:根据给定的字符编码表和context,可以计算出每个单词的摩尔斯编码,到时直接进行匹配即可

因此,定义string codetbl[200]存储字符编码表,其中code[ch]表示字符ch对应的编码串。

定义map<string, vector<string> > ctxt;,其中ctxt[s]表示摩尔斯编码串s对应的可能单词,单词在vector中按输入顺序存放,若改为set,则按字典序排列

接着依次输入摩尔斯密码,根据解码规则处理即可。

注意点

  • 题意不明,经测试,多个精确匹配可输出字典序最小/context中最前面的
  • 模糊匹配一定存在,因为题目仅考虑在字符串末尾增加或减少若干个字符

AC代码(C++11,解密模拟,逆向思维,map)

#include<bits/stdc++.h>
using namespace std;
string codetbl[200], code, s;
char ch;
// map<string, set<string> > ctxt; // 上下文,字典序排列
map<string, vector<string> > ctxt; // 上下文,输入顺序排列
int main() {
    while (cin >>ch && ch != '*') {
        cin >>code; codetbl[ch] = code;
    }
    while (cin >>s && s != "*") {
        string st;
        for (auto c : s) st += codetbl[c];
        // ctxt[st].insert(s); // 字典序排列
        ctxt[st].push_back(s);
    }
    while (cin >>s && s != "*") {
        if (ctxt.find(s) != ctxt.end()) { // 存在
            cout <<*ctxt[s].begin();
            if (ctxt[s].size() > 1) cout <<"!";
        }
        else { // 不存在
            int minlen = 0x3ffff; string ans;
            for (auto p : ctxt) {
                if (s == p.first.substr(0,s.size()) || p.first == s.substr(0,p.first.size())) { // 前缀
                    int i = abs((long)p.first.size()-(long)s.size()); 
                    if (minlen >= i) {
                        minlen = i;
                        ans = *p.second.begin();
                    }
                }
            }
            cout <<ans<<"?";
        }
        puts("");
    }
    return 0;
}
发布了73 篇原创文章 · 获赞 83 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_40738840/article/details/104155668
今日推荐