思路分析
对每个元素进行封装,三个成员分别是标签label、属性id、缩进数level。元素的标签、属性和缩进数可以通过字符串处理得到。如果没有属性id就将其置为空。另外,标签名对大小写不敏感所以可以统一将标签名转化为小写方便后期处理。
查询过程中,查询内容有可能是一个节点也可能是个路径,首先使用strtok函数将查询内容分割,并且将分割的路径上的各个节点存到vector< string> ask中,同样将标签转化为小写。之后从ask中最后一个元素找起,也就是从最小辈的孩子找起,一层一层往上找。
代码实现
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
struct node{
string lable,id;//标签、属性
int level;//缩进
}a[maxn];
bool search(node a[],int &begn,int &cnt,string s){
for(int i=begn;i>=1;i--){
if(a[i].level<cnt){
cnt=a[i].level,begn=i;//保证a[i]是它的父亲即第一个缩进小于它
if(s==a[i].lable||s==a[i].id) return true;
}
}
return false;
}
int main(){
int n,m;string s;
cin>>n>>m;
getchar();
for(int i=1;i<=n;i++){
getline(cin,s);
int pos1=-1,pos2=-1,cnt=0;//分别表示标签和属性的起始位置,缩进
for(int j=0;j<s.size();j++){//以下过程就是将标签和属性分割开
if(s[j]=='.') cnt++;
else if(pos1==-1&&s[j]!='#') pos1=j;//标签位置
else if(s[j]=='#') pos2=j;//属性位置
a[i].level=cnt;
}
if(pos2==-1){//无id
a[i].lable=s.substr(pos1);a[i].id="";
}
else{
a[i].lable=s.substr(pos1,pos2-pos1-1);
a[i].id=s.substr(pos2);
}
//label大小写不敏感,则统一换成小写
for(int k=0;k<a[i].lable.size();k++) a[i].lable[k]=tolower(a[i].lable[k]);
}
//查询
for(int i=0;i<m;i++){
char tmp[100];//存储输入的要查询的内容
vector<string> ask;vector<int> res;//分别存储分割后不同缩进的查询、查询结果
gets(tmp);//不能用getline
char *token=strtok(tmp," ");//返回第一个用空格分割的子字符串
while(token){
ask.push_back(token);
token=strtok(NULL," ");//strtok的用法
}
int len=ask.size();
for(int j=0;j<len;j++){
if(ask[j][0]!='#'){//不是属性,则将标签转化为小写
for(int k=0;k<ask[j].size();k++) ask[j][k]=tolower(ask[j][k]);
}
}
//遍历寻找
for(int j=1;j<=n;j++){
if(ask[len-1]==a[j].id||ask[len-1]==a[j].lable){
int begn=j,cnt=a[j].level,k=len-2;
for(;k>=0;k--)
if(!search(a,begn,cnt,ask[k])) break;
if(k<0) res.push_back(j);//查找成功
}
}
cout<<res.size();
for(int j=0;j<res.size();j++) cout<<" "<<res[j];
cout<<"\n";
}
return 0;
}
题目总结
掌握大量的string和cstring中的函数是处理字符串的必备基础。比如在此题中的substr和strtok函数往常比较少用,但却能带来极大方便,str.substr(pos)是截取字符串str从位置pos开始之后的所有子字符串,substr(pos,cnt)是截取字符串str从位置pos开始包含cnt个字符的子字符串。
strtok(cc," ")返回字符数组cc根据空格分割而成的第一个子字符串的。常用方式如下:
char *token=strtok(tmp," ");//返回第一个用空格分割的子字符串
while(token){
ask.push_back(token);
token=strtok(NULL," ");//strtok的用法
}