5-10 UVA 1597 Searching the Web在Web中搜索

大体题意:

输入许多文章,在输入许多命令,按照指定的格式输出文章或者对应的行。文章最多100个,最多总共1500行,命令最多50000个!

16751099 1597 Searching the Web Accepted C++ 1.048 2016-01-25 03:10:22
思路:

看上去数据量有点小,怎么做都行,但第一遍就TLE了,如果输入一个命令,在全文搜索一遍,这样做不行的,会超时,所以不能直接扫描string

所以又得不用string的find,而且能查找,自然就先想到了map映射!

无意中看到了原文中给的图片!其实查找方法在图片已经体现出来了!


每一个单词都可以映射到指定的文章序号和行序号!但由于可以有重复的单词,所以可以建立一个vector一个一个存取。

所以可以建立一个map<string,vector<pair<int,int> > >,键是指定的单词,值是pair数组,而pair first是文章序号,pair second是行序号!

这一个map就可以解决除了NOT的问题!可以解决3个指令!

而NOT可以根据文章序号查找单词!

所以在建立一个map<string,vector<int> >dest[maxn],dest数组的索引就是文章的序号,string就是第i文章的单词,映射到行数!这样就可以解决NOT指令了

NOT是输出整个文章,其余是对应的行,所以把每一行存到vector<string>String,存进去的是原内容,而映射的都是小写单词!

输出整个文章需要得到,一个文章的开始行数和结尾行数,为了避免循环找行数,所以可以直接建立一个pair<int,int>lines[maxn], lines数组索引为文章的序号,first为起始位置,second为结束位置!在输入的时候就记录!

技巧:

1.可以把只有一个单词的命令当作OR来处理,第一个单词是原单词,第二个单词是文章不可能存在的单词  比如:^_^!!

2.把AND和OR指令写成一个函数,把NOT写成一个函数!

3.在输出时因为是按行数从小到大输出的, 而且不重复输出同一行,但上面的判断会得到同一行,所以可以把上面得到的判断的行数存到set里这样即从小到大排了序,而且没有重复!在根据set输出即可!

让我不爽的是,第二遍是WA,原因就是分隔符“-”是10个,自己打成了9个,但样例输出就是9个啊,但在原文阐述中,确实是10个,!!

代码如下:

#include<string>
#include<iostream>
#include<set>
#include<vector>
#include<map>
#include<sstream>
#include<cctype>
using namespace std;
int n,T;
const int maxn = 1500 + 10;
const string sep[3] = {"**********","----------","=========="};
pair<int,int>lines[maxn];
vector<string>String;
map<string,vector<pair<int,int> > >word;
map<string,vector<int> >dest[maxn];
void deal(const string &s,const string &t,const string & flag){
    int kase = 0;
    for (int i =0 ;i < n; ++i){
        set<int>out;out.clear();
        bool flag_s=false,flag_t=false;
        if (dest[i].count(s)){for(int k=0;k<dest[i][s].size();++k)out.insert(dest[i][s][k]);flag_s=true;}
        if (dest[i].count(t)){for(int k=0;k<dest[i][t].size();++k)out.insert(dest[i][t][k]);flag_t=true;}
        if (flag == "OR"){
            if (flag_s || flag_t){
                if (kase++)cout << sep[1] << endl;
                for (set<int> :: iterator it = out.begin();it != out.end(); ++it)cout << String[*it] << endl;
            }
        }else{
            if (flag_s && flag_t){
                if (kase++)cout << sep[1] <<endl;
                for (set<int>::iterator it = out.begin();it != out.end(); ++it)cout << String[*it] << endl;
            }
        }
    }
    if (!kase)cout << "Sorry, I found nothing." << endl;
    cout << sep[2] <<endl;
}
void deal2(const string &s){
    int kase = 0;
    set<int>out;out.clear();
    for (int i = 0; i < n; ++i){if (!dest[i].count(s)){out.insert(i);kase++;}}
    for (set<int>::iterator it = out.begin(); it != out.end(); ++it){
        if(it != out.begin())cout << sep[1] <<endl;
        for (int i = lines[*it].first; i < lines[*it].second; ++i)cout << String[i] << endl;
    }
    if (!kase)cout << "Sorry, I found nothing." << endl;
    cout << sep[2] << endl;
}
int main()
{
    string s,t,h;
    cin >> n;
    getline(cin,s);
    for (int i = 0; i < n; ++i){
        int cnt = 0;
        while(getline(cin,s) && s != sep[0]){
            if (!cnt){lines[i].first=String.size();if (i)lines[i-1].second=String.size();}
            ++cnt;
            String.push_back(s);
            for (int j=0; j<(int)s.size();++j){if (!isalpha(s[j]))s[j]=' ';else s[j] = tolower(s[j]);}
            stringstream ss(s);
            while(ss >> t){
                pair<int,int>temp;temp.first=i;temp.second=String.size()-1;
                if (!word.count(t))word[t]=vector<pair<int,int> >();
                word[t].push_back(temp);
                if (!dest[i].count(t))dest[i][t]=vector<int>();
                dest[i][t].push_back(String.size()-1);
            }
        }
    }lines[n-1].second=String.size();
    cin >> T;
    getline(cin,s);
    while(T--){
        getline(cin,h);
        int AND = h.find("AND"),OR = h.find("OR"),NOT = h.find("NOT");
        if (AND != -1){s=h.substr(0,AND-1);t=h.substr(AND+4);deal(s,t,"AND");}
        else if (OR != -1){s=h.substr(0,OR-1);t=h.substr(OR+3);deal(s,t,"OR");}
        else if (NOT != -1){s=h.substr(NOT+4);deal2(s);}
        else {s=h;t="^_^!",deal(s,t,"OR");}
    }
    return 0;
}




  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值