Searching the Web——UVA - 1597

也可以查看这里

题目链接

题意:给出n篇文章,每篇文章有若干行,文章与文章之间用**********分开,再给出m个查询,查询分为四种:
1、A:查询所有包含A的那一行字符串
2、A AND B:查询一篇文章中同时包含A和B,A或B所在的那一行
3、A OR B:查询包含A或B所在的那一行
4、NOT A:查询不包含A的文章
在输出结果的时候,不同文章之间的行用----------分开,注意这里是10个符号,链接里面的输出数据里面只给了9个,被这个坑惨了(´இ皿இ`) ,不同的查询之间用==========分开,也是10个。

思路:
1、首先用vector数组保存所有字符串,同一片文章的所有行保存在一个vector中
2、在读取每一篇文章的每一行的时候,进行大小写转换,但不是将转换后的字符串保存在vector中,转换之后利用stringstream读取每一个单词,之后将这个单词所在的文章标号和行数保存在一个map中,map的键是string类型,值是vector<pair<int,int>>类型。
3、读取每一个操作,判断是哪种操作,利用set和集合的交并补即可AC

个人总结:
1、begin、end、rbegin、rend他们的区别
2、集合的操作

代码:

#include <set>
#include <map>
#include <vector>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 150;
typedef pair < int , int > PII;

int n , m;
set < PII > res;
string s , t , op;
vector < string > arts[N]; // 储存所有的文章
map < string , vector< PII > > loc; //储存每一个单词所在的位置

int main(void)
{
    cin >> n;getchar();
    for(int i = 0 ; i < n ; ++ i)
    {
        int line = 0;
        while(getline(cin , s) , s[0] != '*')
        {
            arts[i].push_back(s);//第i篇文章的标号也就是i

            int len = s.length();
            for(int i = 0 ; i < len ; ++ i)//大小写转换
            {
                if(!isalpha(s[i])) s[i] = ' ';//如果不是一个字母,直接转成空格

                else s[i] = tolower(s[i]);
            }
            stringstream in(s);//利用stingstream读取单词
            while(in >> s) loc[s].push_back({i , line});//记录每个单词所在的文章和行数
            line ++;
        }
    }

    cin >> m;getchar();
    while(m --)
    {
        res.clear();

        getline(cin , op);

        int a = op.find(' ') , b = op.rfind(' ');//分别从前往后和从后往前找到两个空格的位置
        if(a != string::npos && b != string::npos && a != b && b - a - 1 == 3)//如果是AND查询
        {
            set < int > s1 , s2;

            s = op.substr(0 , a);
            t = op.substr(b + 1);

            res.insert(loc[s].begin() , loc[s].end());//先将所有包含s和t的 编号及对应的行数添加到结果集合中
            res.insert(loc[t].begin() , loc[t].end());

            for(auto i : loc[s]) s1.insert(i.first);//s1保存所有s出现的文章
            //找到交集
            for(auto i : loc[t])
                if(s1.find(i.first) != s1.end())
                    s2.insert(i.first);//s2保存的是所有同时有s和t的文章的编号
            auto backup = res;//这里要先备份一下
            for(auto i : backup)//删除
                if(s2.find(i.first) == s2.end())
                    res.erase(i);
        }
        else if(a != string::npos && b != string::npos && a != b && b - a - 1 != 3)//OR查询
        {
            s = op.substr(0 , a);
            t = op.substr(b + 1);
            //or查询直接插入即可
            res.insert(loc[s].begin() , loc[s].end());
            res.insert(loc[t].begin() , loc[t].end());
        }

        else if(a != string::npos && b != string::npos && a == b)//NOT查询
        {
            //NOT查询要单独输出
            s = op.substr(4);

            set < int > art;
            for(int i = 0 ; i < n ; ++ i)art.insert(i);
            for(auto i : loc[s])
                art.erase(i.first);//操作之后,art变为所有不包含s的文章编号
                
            for(auto i : art)//对于NOT操作要输出整篇文章
            {
                for(auto j : arts[i]) cout << j << endl;
                if(i != *art.rbegin()) puts("----------");
            }
            if(art.empty()) puts("Sorry, I found nothing.");
            puts("==========");
            continue;
        }
        else//第一种操作
        {
            s = op;
            res.insert(loc[s].begin() , loc[s].end());
        }

        int pre = -1;
        for(auto i : res)
        {
            if(i.first != pre && pre != -1) puts("----------");
            pre = i.first;
            cout << arts[i.first][i.second] << endl;
        }
        if(res.empty()) puts("Sorry, I found nothing.");
        puts("==========");

    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值