紫书第五章习题 5-10 UVa1597-searching the web

出处:https://blog.csdn.net/u014800748/article/details/44624989

题目链接:https://vjudge.net/contest/231030#problem/J

本题要求模拟一个搜索引擎,该引擎可以处理四种搜索方式:term,term1 AND term2,term1 OR term2,NOT term。在题目描述部分已经介绍了搜索引擎的搭建方式,理论上只需要按照题意搭建即可,不过这样的话,代码会很长,由于中间还要输出一些分隔符来区分文章或者询问,代码长度至少快300行了。这样的代码难以维护,而且在比赛中也不切实际,因此需要进行再优化。

由于需要建立每个关键词和对应的文章,段落的映射,因此想到可以使用map。为了便于处理,这里指记录关键词与行之间的映射关系,同时用limit数组来标记每篇文章的边界行。由于一共有四种查询方式,为了便于处理不同的查询方式,再设一个mark数组,来标记该查询方式下的行号。

那么最后一个问题,如何处理两种不同的分隔符。通过观察可以发现,dash分隔符出现在上一次有输出的情况下,equal分隔符出现在每次查询的末尾。这样以来,只需要用两个标记变量hasOut,needOut来判断上一次是否有过输出并且dash分隔符是否需要输出即可,具体实现方式见代码注释。

本题的一个重要技巧是定义Bit来表示一个所有行的标记数组,即 tyoedef bool Bit[1505],还有一个技巧是活用逻辑运算符来计算mark数组。另外需要注意输入n,m时要多打一个空格,抵消掉换行符,否则会WA。


    #define _CRT_SECURE_NO_WARNINGS   
    #include<iostream>  
    #include<algorithm>  
    #include<string>  
    #include<sstream>  
    #include<set>  
    #include<vector>  
    #include<stack>  
    #include<map>  
    #include<queue>  
    #include<deque>  
    #include<cstdlib>  
    #include<cstdio>  
    #include<cstring>  
    #include<cmath>  
    #include<ctime>  
    #include<functional>  
    using namespace std;  
      
    #define N 1505  
    #define rep(i,n) for(int i=0;i<(n);i++)  
    #define FOR for(int j=limit[i];j<limit[i+1];j++)  
    typedef bool Bit[N];  
    map<string, Bit>Index;  
    string doc[N];  
    int limit[105];  
    int n, lines, m;  
    void update(string s, int p)  
    {  
        string word;  
        string::iterator it = s.begin();  
        for (it; it != s.end();it++)  
        if (isalpha(*it))*it = tolower(*it);  
        else *it = ' ';  
        stringstream ss(s);  
        while (ss >> word)Index[word][p] = true;  
    }  
    int main() {  
        //文档数据输入  
        //freopen("t.txt", "r", stdin);  
        scanf("%d ", &n);//注意,要多打一个空格,抵消掉换行符  
        rep(i, n) {  
            limit[i] = lines;  
            while (getline(cin, doc[lines]), doc[lines] != "**********") {  
                update(doc[lines], lines);  
                lines++;  
            }  
        }  
        limit[n] = lines;//为了便于用FOR统一处理  
      
        //对获取的请求输出对应的内容  
        string  s;                      // s存储每次得到的请求  
        Bit     mark;                   //记录哪些行应该输出  
        //mark的解释: 因为每篇文档要用10个'-'隔开,比较麻烦,最后统一处理  
        bool    *A, *B;  
      
        scanf("%d ", &m);//多打一个空格,方便处理多余的字符  
        while (m--)  
        {  
            getline(cin, s);  
      
            //计算出mark中介  
            if (s[0] == 'N')   
            {  
                A = Index[s.substr(4)];  
                rep(i, n) {  
                    bool logo = true;  
                    FOR if (A[j]) { logo = false; break; }  
                    FOR mark[j] = logo;  
                }  
            }  
            else if (s.find("AND") != string::npos)   
            {  
                int p = s.find(" AND ");  
                A = Index[s.substr(0, p)];  
                B = Index[s.substr(p + 5)];  
                memset(mark, 0, sizeof(mark));  
                bool hasA, hasB;    // 在同一文章中, 两个词是否都出现  
                rep(i, n)   
                {  
                    hasA = hasB = false;    // 默认没出现  
                    FOR if (A[j]) { hasA = true; break; }  
                    FOR if (B[j]) { hasB = true; break; }  
                    if (!(hasA&&hasB)) continue;  
                    FOR mark[j] = (A[j] || B[j]);  
                }  
            }  
            else if (s.find("OR") != string::npos)   
            {  
                int p = s.find(" OR ");  
                A = Index[s.substr(0, p)];  
                B = Index[s.substr(p + 4)];  
                rep(i, lines) mark[i] = (A[i] || B[i]);  
            }  
            else memcpy(mark, Index[s], sizeof(mark));  
      
            //{subsection: 输出mark  
            bool hasOut = false, needOut = false;    // 记录上一轮是否有输出文档  
            rep(i, n)   
            {  
                if (hasOut) needOut = true;  
                hasOut = false;  
                FOR if (mark[j])   
                {  
                    if (needOut)   
                    {  
                        cout << "----------\n";  
                        needOut = false;  
                    }  
                    cout << doc[j] << "\n";  
                    hasOut = true;  
                }  
            }  
            if (!(needOut || hasOut)) cout << "Sorry, I found nothing.\n";//如果有过输出,必然有一个为true  
            cout << "==========\n";  
        }  
        return 0;  
    }  

猜你喜欢

转载自blog.csdn.net/JXUFE_ACMer/article/details/80465190