201809-3 元素选择器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
思路:
这题也是一个大模拟题,我们从数据类型,搜索过程,细节处理三个方面进行分析。
数据类型
结点的结构体,存储了当前行的标签和id,以及父亲节点。

struct node{
    node(){
        key.clear(); id.clear(); parent=0;
    }
    string key;//标签选择器
    string id;//id选择器
    int parent;//父亲
};
node a[maxn];

细节处理
使用map存储一个string对应的行号是多少,由于标签可能有多个相同的,所以用一个string对应一个vector。当然,这个map中也存储了id,不过vector的size=1。
使用数组level存储上一个第i层的节点的行号。
标签大小写不敏感,id大小写敏感。
搜索过程
我们搜索div div p,那么首先通过map找到所有p对应的行号,也就是节点的序号,然后遍历这些序号,通过这个节点,搜索向上父亲节点,直到搜索到根节点或者三个标签都找到了,那么这个序号就是正确的,存起来,遍历下一个序号即可。
代码:

#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <sstream>
using namespace std;

const int maxn=105;
struct node{
    node(){
        key.clear(); id.clear(); parent=0;
    }
    string key;//标签选择器
    string id;//id选择器
    int parent;//父亲
};
node a[maxn];
int n,m,cnt;
map<string,vector<int>> mp;
int level[maxn];
void SplitAndBuild(string _s){
    int _level=0,_temp; string _key,_id; _key.clear(); _id.clear();
    for (int i=0; i<_s.size(); i++){
        _temp=0;
        while(_s[i]=='.'){
            _temp+=1; i+=2; _level=_temp;
        }
        if(_temp){
            i--; continue;
        }
        if(_s[i]==' '){
            _key=_id; _id.clear(); continue;
        }
        _id+=_s[i];
    }
    if(_key.empty()){
        _key=_id; _id.clear();
    }
    for (int i=0; i<_key.size(); i++){
        if(_key[i]>='A' && _key[i]<='Z') _key[i]+=32;
    }
    a[++cnt].key=_key; a[cnt].id=_id; level[_level]=cnt;
    mp[_key].push_back(cnt); if(!_id.empty()) mp[_id].push_back(cnt);
    if(_level) a[cnt].parent=level[_level-1];
}
bool backtrack(int nodeindex,vector<string> _v,int index){
    if(index==-1) return true;
    if(nodeindex==0) return index==-1;
    if(a[nodeindex].id==_v[index] || a[nodeindex].key==_v[index])
        return backtrack(a[nodeindex].parent,_v,index-1);
    else return backtrack(a[nodeindex].parent,_v,index);
}
void find(string _s){
    vector<string> v; v.clear();
    string stemp; stemp.clear();
    stringstream ss(_s);
    while(getline(ss,stemp,' ')){
        if(!stemp.empty()) {
            if(stemp[0]!='#'){
                for (int i=0; i<stemp.size(); i++){
                    if(stemp[i]>='A' && stemp[i]<='Z') stemp[i]+=32;
                }
            }
            v.push_back(stemp);
        }
    }
    vector<int> line; line.clear();
    for (int i=0; i<mp[v[v.size()-1]].size(); i++){
        if(backtrack(mp[v[v.size()-1]][i],v,v.size()-1))
            line.push_back(mp[v[v.size()-1]][i]);
    }
    printf("%lu",line.size());
    for (auto it:line) printf(" %d",it);
    putchar('\n');
}
int main(){
    scanf("%d %d",&n,&m); getchar();
    for (int i=1; i<=n; i++){
        string s; getline(cin,s);
        SplitAndBuild(s);
    }
    for (int i=1; i<=m; i++){
        string s; getline(cin,s);
        find(s);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值