CCF201809-3-元素选择器

(一)题面:

 

(二)题意:

(中文题见题面)。

 

(三)题解:

其实一看到那个文档的表示方式,就很容易想到可以用一颗数来表示,查询时直接遍历树即可。

1、树结点:每个节点保存一行的标签和id属性,其结点编号为所在行号,即每行一个结点。

2、建树:这里建树可能有两个思路,一个是递归建树,即建树边输入,这个在实际的操可能比较麻烦(可能要回溯到很久以前的结点),另一个是插入式,即每输入一行将对应信息插入到对应的位置,这里考虑如何找到插入的位置:由于每一个结点编号都是一个行号,我们在插入某一个结点时,只要知道其前一级(最近的祖先元素)的那一行对应的行号(用一个数组进行保存和更新即可),然后遍历树找到对应结点,再插入到后面即可。

3、查询:对于非复合的查询直接遍历树的所有结点,判断结点信息是否满足查询,满足就保存编号。对于复合查询,我们遍历树的时候在路径上依次匹配,即按照提示的所说的贪心地去匹配即可,当除了最后一个之外全部匹配完以后,将后面的可以与最后一项匹配的结点编号全部保存即可。

实际上这两种操作再进行匹配时可以统一,具体见代码。

4、输出。

 

(四)代码:

#include<iostream>
#include<sstream>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
const int maxn=201;
void norm_tag(string &s){                  //标签全部变为小写
    int l=s.length();
    for(int i=0;i<l;i++)
        if(s[i]>='A'&&s[i]<='Z')s[i]+=32;
}
struct tree_node{                          //树的结点
    string tag,id;
    void init(string _tag,string _id){
        tag=_tag;id=_id;norm_tag(tag);
    }
};
struct Tree{
    int level_info[maxn],nt;               //level_info[i]表示当前层次为i的行号
    vector<int>tree[maxn];                 //存树
    tree_node info[maxn];                  //各个结点的具体信息
    vector<int>ans;                        //最终结果
    Tree(){nt=1;memset(level_info,0,sizeof level_info);}
    void insert(string _tag,string _id,int lv,int rt,int pos){
                                           //插入
        if(rt==pos){                       //找到了对应位置
            tree[rt].push_back(nt);
            info[nt].init(_tag,_id);
            level_info[lv]=nt++;return;    //更新信息
        }
        for(int i=0;i<tree[rt].size();i++)
            insert(_tag,_id,lv,tree[rt][i],pos);
    }
    void query(string s[],int len,int rt,int pos){
                                           //查询
        if(s[pos]==info[rt].tag||s[pos]==info[rt].id){
                                           //匹配
            if(pos==len-1)ans.push_back(rt);
            else pos++;                    //下一个
        }
        for(int i=0;i<tree[rt].size();i++)
            query(s,len,tree[rt][i],pos);
    }
    void output(){
        cout<<ans.size();
        sort(ans.begin(),ans.end());
        for(int i=0;i<ans.size();i++)
            cout<<' '<<ans[i];cout<<'\n';
    }
}solve;
int main(){
    int n,m;cin>>n>>m;
    string str;getchar();
    for(int i=0;i<n;i++){
        getline(cin,str);
        int p1=str.find_first_not_of('.'),p2=str.find(' ');
        int lv=p1/2+1,l=str.length();
        string tg,id;
        if(p2!=string::npos){
            tg=str.substr(p1,p2-p1);
            id=str.substr(p2+1,l);
        }
        else {tg=str.substr(p1,l);id="";}
        solve.insert(tg,id,lv,0,solve.level_info[lv-1]);
    }string s[101],ss;
    for(int i=0,t=0;i<m;i++,t=0){
        getline(cin,str);stringstream in(str);
        while(in>>ss){
            if(ss[0]!='#')norm_tag(ss);s[t++]=ss;
        }
        solve.ans.clear();solve.query(s,t,0,0);solve.output();
    }
    return 0;
}

 

(五)总结:

相对而言是比较简单的第三题了,但是当时想着递归建树...,然后一直没写出来。

也不一定见得要建树,实际上直接用数组去模拟也挺简单的,最后就这么写骗了点分。

当时有点写郁闷了,一直建不出树。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值