1.题意
2.解题思路
- 首先是存储问题,一开始我想用一个结构体存储它的父节点,子节点,标签,id,但是比较繁琐,并且n<100数据非常小,所以适合遍历搜索根据“.”的数量cnt,所以结构体中仅需存储标签,id,cnt,并且行号已经由vector下标记录了所以不用存行号。
- 读取数据问题,无论是文档还是查询都需要正行读入,这就用到了getchar(),getline(),gets()以及在对查询分id或标签时就要用到strtok()函数,返回一个指针,调用完需要将指针赋空,且指向分割符
- 关于选择器问题,可以根据提示找层次低的即自底向上遍历找符合条件的,同时应当注意到,无论是何种选择器,都是寻找标签或id匹配的,所以没有必要分开来讨论,只是后代选择器多找了几层
- 总结:一开始做题时,有很多地方不知道该怎样写,因为是树结构在考虑记录父子节点,但这不是算法题且数据很少不需要一下全部处理好,可以进行适当遍历寻找;还是要仔细读题和样例,不能误解题意;最后关于读数据以及分割数据,对string的操作还需要更加熟悉,需要及时复习关于string的相关知识点尤其是各种函数用法
3.AC代码
#include<stdio.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
struct css{
int cnt;
string bq;
string id;
css(int b,string c,string d)
{
cnt=b;
bq=c;
id=d;
}
};
vector<css>v;
bool search(int &start,string s)
{
int cnt=v[start].cnt;
for(int i=start;i>=0;i--)
{
if(v[i].cnt<cnt)
{
cnt=v[i].cnt,start=i;
if(s==v[i].bq||s==v[i].id) return true;
}
}
return false;
}
int main()
{
int n,m,count,last;
string str,bq,id;
cin>>n>>m;
getchar();//读取换行符
for(int i=0;i<n;i++)
{
getline(cin,str);
bool flag=false;
int cnt=0;
bq="",id="";
for(int j=0;j<str.size();j++)
{
if(str[j]=='.') cnt++;
if(str[j]=='#'||flag==true)
{
flag=true;
id+=str[j];
}
if(str[j]!='.'&&str[j]!=' '&&flag==false)
{
bq+=str[j];
}
}
for(int j=0;j<bq.size();j++)
{
bq[j]=tolower(bq[j]);
}
v.push_back(css(cnt,bq,id));
}
for(int i=0;i<m;i++)
{
char tmp[100];
vector<string>q;
vector<int>ans;
gets(tmp);
char *p=strtok(tmp," ");
while(p)
{
q.push_back(p);
p=strtok(NULL," ");
}
for(int j=0;j<q.size();j++)
{
if(q[j][0]!='#')
{
for(int k=0;k<q[j].size();k++)
{
q[j][k]=tolower(q[j][k]);
}
}
}
int l=q.size();
for(int j=0;j<n;j++)
{
if(q[l-1]==v[j].id||q[l-1]==v[j].bq)
{
int start=j,k=l-2;
for(;k>=0;k--)
{
if(!search(start,q[k])) break;
}
if(k<0) ans.push_back(j+1);
}
}
cout<<ans.size();
for(int j=0;j<ans.size();j++)
{
cout<<" "<<ans[j];
}
cout<<endl;
}
return 0;
}