UVA ~ 1597 ~ Searching the Web (模拟,map+bitset)

本文介绍了一种用于处理大规模文本集合的高效搜索算法。通过使用vector和bitset数据结构,结合map来记录关键字出现的位置,实现了对文章集合进行快速精确匹配的能力。支持AND、OR、NOT等多种查询条件,并详细展示了如何实现这些功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:输入n篇文章和m个请求(n < 100, m≤50000),每个请求都是以下四种格式之一。

1.A:查找包含关键字A的文章。(即如果某篇文章中含有A,输出含有A的行)

2.A AND B:查找同时包含关键字A和B的文章。(即如果某篇文章中含有A和B,输出含有A的行,或含有B的行)

3.A OR B:查找包含关键字A或B的文章。(即如果某篇文章中含有A或B,输出含有A的行,或含有B的行)

4.NOT A:查找不包含关键字A的文章。(即如果某篇文章不含有A,输出整篇文章)

关键字只有小写字母组成,查找时忽略大小写。每行不超过80个字符,一共不超过1500行。

思路:vector一行一行保存原文,limit[i]保存第i篇文章在哪一行之前,用map<string, bitset<1050> >表示某个单词word,在那些行中出现过。输出比较麻烦,我们先把所有行的输出状态的处理到一个out中,然后在输出。输出的时候立两个flag,has_out表示之前是否有输出,need_out表示该篇文章是否需要输出。


#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1505;
int n, m;
vector<string> Article;//文章
map<string, bitset<MAXN> > M;//单词在第几行
int limit[105] = {0}; //第i篇文章在第几行之前
void Insert(string str,int row)
{
    for (auto &i: str)//字母转化为小写,符号化为空格
    {
        if (isalpha(i)) i = tolower(i);
        else i = ' ';
    }
    stringstream ss(str);
    string word;
    while (ss >> word) M[word].set(row, 1);//单词出现的行设置为1
}
int main()
{
    //ofstream cout("out.txt");
    string str;
    cin >> n; cin.get();//读取回车
    int row = 0;
    for (int i = 1; i <= n; i++)
    {
        while (getline(cin, str) && str != "**********")
        {
            Article.push_back(str);//保存原文
            Insert(str, row);//处理这一行
            row++;//第row行
        }
        limit[i] = row;
    }
    cin >> m; cin.get();//读取回车
    while (m--)//m次操作
    {
        getline(cin, str);
        bitset<MAXN> A, B, out;//关键字A,B对应的行的状态,out为行的输出状态
        if (str.find(" AND ") != string::npos)
        {
            A = M[str.substr(0, str.find(" AND "))], B = M[str.substr(str.find(" AND ") + 5)];
            for (int i = 1; i <= n; i++)
            {
                bool flag1 = false, flag2 = false;//本篇文章中关键字A,B是否出现过
                for (int j = limit[i - 1]; j < limit[i]; j++)//本篇文章对应的行
                {
                    if(A[j]) { flag1 = true; }
                    if(B[j]) { flag2 = true; }
                }
                if (flag1 && flag2)//关键字A,B都出现过
                {
                    //处理需要输出的行,即A或者B在的行
                    for (int j = limit[i - 1]; j < limit[i]; j++) out[j] = A[j] || B[j];
                }
            }
        }
        else if (str.find(" OR ") != string::npos)
        {
            A = M[str.substr(0, str.find(" OR "))], B = M[str.substr(str.find(" OR ") + 4)];
            for (int i = 1; i <= n; i++)
            {
                bool flag1 = false, flag2 = false;//本篇文章中关键字A,B是否出现过
                for (int j = limit[i - 1]; j < limit[i]; j++)//本篇文章对应的行
                {
                    if(A[j]) { flag1 = true; }
                    if(B[j]) { flag2 = true; }
                }
                if (flag1 || flag2)//A出现过或者B出现过
                {
                    //处理需要输出的行,即A或者B在的行
                    for (int j = limit[i - 1]; j < limit[i]; j++) out[j] = A[j] || B[j];
                }
            }
        }
        else if (str.find("NOT ") != string::npos)
        {
            A = M[str.substr(str.find("NOT ") + 4)];
            for (int i = 1; i <= n; i++)
            {
                bool flag1 = false;
                for (int j = limit[i - 1]; j < limit[i]; j++)//第i篇文章对应的行
                {
                    if(A[j]) { flag1 = true; }
                }
                if (!flag1)//本篇文章没出现过
                {
                    //处理需要输出的行,即本篇文章对应所有的行
                    for (int j = limit[i - 1]; j < limit[i]; j++) out[j] = true;
                }
            }
        }
        else { out = M[str]; }//关键字A所在的行即要输出的行
        //输出
        bool has_out = false;//之前有没有输出
        for (int i = 1; i <= n; i++)
        {
            bool need_out = false;//本篇文章是否需要输出
            for (int j = limit[i - 1]; j < limit[i]; j++)
            {
                if (out[j]) { need_out = true; break; }
            }
            if (need_out)//需要输出
            {
                if(has_out) cout << "----------" << endl;//如果之前有输出那么就输出一行分割线
                for (int j = limit[i - 1]; j < limit[i]; j++)//遍历输出
                {
                    if (out[j]) cout << Article[j] << endl;//需要输出就输出原来的文章
                }
                has_out = true;
            }
        }
        if (!has_out) cout << "Sorry, I found nothing." << endl;//没有输出
        cout << "==========" << endl;
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值