2024团体程序设计天梯赛 L2-2 懂蛇语

题目如下:

在《一年一度喜剧大赛》第二季中有一部作品叫《警察和我之蛇我其谁》,其中“毒蛇帮”内部用了一种加密语言,称为“蛇语”。蛇语的规则是,在说一句话 A 时,首先提取 A 的每个字的首字母,然后把整句话替换为另一句话 B,B 中每个字的首字母与 A 中提取出的字母依次相同。例如二当家说“九点下班哈”,对应首字母缩写是 JDXBH,他们解释为实际想说的是“京东新百货”……
本题就请你写一个蛇语的自动翻译工具,将输入的蛇语转换为实际要表达的句子。

输入格式:

输入第一行给出一个正整数 N(≤105),为蛇语词典中句子的个数。随后 N 行,每行用汉语拼音给出一句话。每句话由小写英文字母和空格组成,每个字的拼音由不超过 6 个小写英文字母组成,两个字的拼音之间用空格分隔。题目保证每句话总长度不超过 50 个字符,用回车结尾。注意:回车不算句中字符。
随后在一行中给出一个正整数 M(≤103),为查询次数。后面跟 M 行,每行用汉语拼音给出需要查询的一句话,格式同上。

输出格式:

对每一句查询,在一行中输出其对应的句子。如果句子不唯一,则按整句的字母序输出

句子间用 | 分隔。如果查不到,则将输入的句子原样输出。

注意:输出句子时,必须保持句中所有字符不变,包括空格

输入样例:

8
yong yuan de shen
yong yuan de she
jing dong xin bai huo
she yu wo ye hui shuo yi dian dian
liang wei bu yao chong dong
yi  dian dian
ni hui shuo she yu a
yong yuan de sha
7
jiu dian xia ban ha
shao ye wu ya he shui you dian duo
liu wan bu yao ci dao
ni hai shi su yan a
yao diao deng
sha ye ting bu jian
y y d s

输出样例:

jing dong xin bai huo
she yu wo ye hui shuo yi dian dian
liang wei bu yao chong dong
ni hui shuo she yu a
yi  dian dian
sha ye ting bu jian
yong yuan de sha|yong yuan de she|yong yuan de shen

        解读一下题目,可以看到题目的要求就是让我们存储每个“蛇语”字符串的首字母,组合形成关键字,最后通过这个关键字输出对应要求的字符串。 

        那么首先看到这个题目是字符串的输入输出,可以用C++的string类来存储字符串。这里有一个小坑点是这个字符串是以 行 为单位的,不能通过string类的数组去把一句话拆分成多个单词存储(不然会导致不同单词之间的空格数不同,不好判断),于是我便想出了使用 getline() 来读取整行字符串,随后再对每个单词的首字母进行提取。

        getline()可以读取整行字符的内容,包括空格,然后以回车为结束符并且舍弃这个回车(当然也可以自己设置结束符,即getline()的第三个参数)。在这里的用法是getline(cin, str),其中注意使用之前记得用 getchar() 读掉前边输入数字时多余的回车。

         解决了读入的问题以后,接下来就是思考要用什么数据结构进行存储。题意要求用多个单词的首字母组合作为关键字查询到多个字符串,首先前面“用多个单词首字母组合作为关键字”的要求,可以通过C++的map容器,用键值对存储字符串,比如将字符串 yi  dian dian ydd 存储,同时考虑到一个key可能对应多个字符串,因此可以用set容器作为键值对中对值的存储。

(小坑点:为什么不用vector容器? 因为题意要求按整句的字母序输出,而set底层是由红黑树实现的,可以实现自动排序)

        于是就会出现这样的读取和存储代码:

    int n;
    cin >> n;
    //读掉输入数字时留下的回车
    getchar();
    map<string, set<string> > umps;
    
    for (int i = 0; i < n; ++i){
        string ss;
        // cin >> ss;
        getline(cin, ss);
        //获取各个单词的首字母
        string mark = get_mark(ss);
        umps[mark].insert(ss);
    }

同时,这里获取首字母的实现方式如下:

string get_mark(string& ss)
{
    int pos = 0;
    string mark;
    // 判断字符串开头有没有空格
    if (ss[pos] != ' '){
        mark.push_back(ss[0]);
    }
    // 用string的find()成员函数寻找空格所在的下标,
    // 同时检查该空格前面第一个不为空格的字符
    while (pos != string::npos){
        pos = ss.find(" ", pos);
        if (pos != string::npos){
            if (pos < ss.size() - 1 && 
                ss[pos + 1] != ' '){
                mark.push_back(ss[pos + 1]);
            }
            //偏移一个单位,防止反复找到同一个空格
            ++pos;
        }
    }
    return mark;
}

经过上述的操作以后,我们会得到一个map,在这里可以通过首字母组合可以找到已经排好序的需要输出的set,因此接下来只需要按照要求的格式输出即可

输出时对问题的读入操作与上面的输入时相同

    int k;
    cin >> k;
    getchar();
    for (int i = 0; i < k; ++i){
        string st;
        getline(cin, st);
        string mark = get_mark(st);

        int cnt = 0;
        //如果该字符串在“蛇语词典”中,
        //即首字母组合在map中存在记录
        if (umps[mark].size() > 0){
            //umps是一个map容器,而umps[mark]则是键mark对应的值,是set<string>
            //因此 auto it 取到的是set中的元素,即string本身
            for (auto it : umps[mark]){
                cout << it;
                ++cnt;
                 if (cnt < umps[mark].size())
                     cout << '|';
            }
        }
        else{ //不在“蛇语词典”中的处理:输出原字符串
            cout << st;
        }
        cout << endl;
    }

最终会出现这个结果:

怎么会这样呢(?)

        当理清一遍自己代码的逻辑发现没什么问题的时候,就要想一想有没有什么特例了,可能有的小伙伴在前面读题时就发现了——蛇语词典可能出现相同的字符串!而我们所用的set,是名为集合的容器。众所周知,集合里边是不允许存在相同元素的,因此我们这里可以将set替换为另一个容器multiset,它和set的区别就在于multiset可以允许元素重复。

于是,将set修改为multiset以后再提交:

成功通过

以下是本题完整的C++代码内容:

#include <bits/stdc++.h>

using namespace std;

string get_mark(string& ss)
{
    int pos = 0;
    string mark;
    if (ss[pos] != ' '){
        mark.push_back(ss[0]);
    }
    while (pos != string::npos){
        pos = ss.find(" ", pos);
        if (pos != string::npos){
            if (pos < ss.size() - 1 && 
                ss[pos + 1] != ' '){
                mark.push_back(ss[pos + 1]);
            }
            ++pos;
        }
    }
    return mark;
}

int main (void)
{
    int n;
    cin >> n;
    //读掉输入数字时留下的回车
    getchar();
    // unordered_map<string, unordered_set<string> > umps;
    // unordered_map<string, multiset<string> > umps;
    map<string, multiset<string> > umps;
    
    for (int i = 0; i < n; ++i){
        string ss;
        // cin >> ss;
        getline(cin, ss);
        //获取各个单词的首字母
        string mark = get_mark(ss);
        umps[mark].insert(ss);
    }

    int k;
    cin >> k;
    getchar();
    for (int i = 0; i < k; ++i){
        string st;
        getline(cin, st);
        string mark = get_mark(st);

        int cnt = 0;
        if (umps[mark].size() > 0){
            for (auto it : umps[mark]){
                cout << it;
                ++cnt;
                 if (cnt < umps[mark].size())
                     cout << '|';
            }
        }
        else{
            cout << st;
        }
        cout << endl;
    }
    
    return 0;
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值