嗯,也是折腾了一上午的题啊…好菜啊…其实就是普通的逻辑题,数据范围都很小根本不用担心超,就是把查询逻辑处理好久可以了
主要注意:
- 标签大小写不敏感,id大小写敏感,会在一个测试点里集中测试,只有这个没注意能拿90分(我就在这卡了好久,直到看到一个人的答案才恍然大悟)
- 标签和id是可以混合的,也就是可以 div #two p这样,我不清楚为什么说后代选择器A B均为xxxbalabala的,但实际上数据是混合的
- 搜索的时候注意搜索的时候搜索到的标签之间一定有父子关系,同级元素是不能匹配两个搜索词的。
using namespace std;
#include<cstdio>
#include<string>
#include<list>
#include<stack>
struct xml{//元素的数据结构
string name;
string id;
int parent;
int lid;
int level;
void show(){
printf("'%s' '%s' %d %d %d\n",name.c_str(),id.c_str(),parent,lid,level);
}
};
int judgeLevel(string &s)//根据前面的两个点判断级别,用于确定元素级别和父亲元素
{
int i=0;
for(;i<s.size()&&s[i]=='.';i++){}
return i/2;
}
xml x[101];
bool search(list<string> &keys,int right){
//根据搜索关键词和初始位置从后往前搜索是否存在元素,是和具体的循环体配合的,因此多加了最尾元素的判断
//如果第一个就匹配不了,直接退出
list<string>::iterator cur = keys.end(),ini = keys.begin();//迭代器的应用
cur--;//end指向空,因此要--才是尾元素
if((*cur)!=x[right].id && (*cur)!=x[right].name)
{
//判断尾元素是否匹配,因为外端方法是循环向前遍历,如果从这里贪心就会多匹配一些元素
return false;
}
cur--;
ini--;//begin指向的是第一个元素,cur遍历到begin--时才会
if(cur==ini)//如果迭代完了,说明全都匹配上了
{
return true;
}
right = x[right].parent;
while(right>=0)
{
if((*cur) == x[right].id || (*cur) == x[right].name)
{
cur--;
if(cur==ini)
{
return true;
}
}
right = x[right].parent;//指向父亲,从父亲那开始继续匹配,这也是从尾往前匹配的原因,因为一个元素只可能有一个爸爸
}
return false;
}
bool lower(string &a){
//可以替换到下面的方法实现减少代码量
//但替换后悔增加耗时和空间,具体原理不清楚
//应该是方法传参的细节,也就是如果能少嵌套方法就尽量少嵌套
for(int i = 0;i<a.size();i++)
{
if(a[i]>='A' && a[i]<='Z')
{
a[i] -= 'A'-'a';
}
}
}
int main(){
int n,m;
scanf("%d %d",&n,&m);
getchar();
stack<xml> level;
for(int i = 0;i<n;i++)
{
char cline[80];
scanf("%[^\n]", &cline);getchar();
string line = cline;
int llevel = judgeLevel(line);
int pos = line.find(' ');
xml cur;
if(pos!=-1)//有空格说明有标签和id
{
cur.name = line.substr(llevel*2,pos-llevel*2);
for(int j = 0;j<cur.name.size();j++)//标签大小写不敏感
{
if(cur.name[j]>='A' && cur.name[j]<='Z')
{
cur.name[j]-= 'A'-'a';
}
}
cur.id = line.substr(pos+1,line.size()-pos);
}else//没有说明..分级后是完整的标签
{
cur.name = line.substr(llevel*2,pos-llevel*2);
for(int j = 0;j<cur.name.size();j++)
{
if(cur.name[j]>='A' && cur.name[j]<='Z')
{
cur.name[j]-= 'A'-'a';
}
}
cur.id = "";
}
cur.lid = i;
cur.level=llevel;
//分配父亲,仅在这里使用xml结构中的level属性
//利用栈,栈的大小和级别刚好可以形成对应关系
if(llevel==level.size())
{
if(level.empty())
{
cur.parent = -1;
level.push(cur);
}else{
cur.parent = level.top().lid;
level.push(cur);
}
}else if(llevel<level.size()){
while(llevel != level.size())
{
level.pop();
}
if(level.empty())
{
cur.parent = -1;
level.push(cur);
}else{
cur.parent = level.top().lid;
level.push(cur);
}
}else{}//不可能大于
x[i] = cur;
}
//接收查询词并处理
for(int i = 0;i<m;i++)
{
list<string> keys;
list<int> res;
char ckey[80];
char split;
scanf("%s",ckey);
split = getchar();
string skey = ckey;
skey = ckey;
if(skey[0] != '#')
{
for(int j = 0;j<skey.size();j++)
{
if(skey[j]>='A' && skey[j]<='Z'){
skey[j] -= 'A'-'a';
}
}
}
keys.insert(keys.end(),skey);
while(split == ' ')//分隔符是空格说明还有下一个,否则会接收到换行符
{
scanf("%s",ckey);
skey = ckey;
if(skey[0] != '#')
{
for(int j = 0;j<skey.size();j++)
{
if(skey[j]>='A' && skey[j]<='Z'){
skey[j] -= 'A'-'a';
}
}
}
keys.insert(keys.end(),skey);
split = getchar();
}
//搜索
int num = 0;
int pos;
for(int k = n-1;k>=0;k--)
{
pos = search(keys,k);
if(pos)
{
res.insert(res.begin(),k+1);
num++;
}
}
//输出
printf("%d ",num);
for(list<int>::iterator iter = res.begin(),next;iter!=res.end();iter++)
{
next = iter;
next++;
if(next != res.end())
{
printf("%d ",*iter);
}else
{
printf("%d",*iter);
}
}
printf("\n");
}
return 0;
}
2019年9月3日第二次刷,更好的代码:
#include <bits/stdc++.h>
using namespace std;
struct css{
int index;
int parent;
int level;
string name;
string id;
}e[102];
bool equal(css &ae,string &s){
return ae.name == s || ae.id == s;
}
int n,m;
bool find(int cur,vector<string> &v){
int p = 0;
int i = cur;
while(i>=0){
if(equal(e[i],v[p])){
p++;
}else if(p == 0)//非常关键的一步判断
{
return false;
}
i = e[i].parent;
if(p>v.size()-1) {
return true;
}
}
return false;
}
int main(){
scanf("%d %d",&n,&m);
stack<css> s;
char block[2000];
int level;
char split;
for(int i = 0;i<n;i++)
{
scanf("%*[.]%n",&level);
scanf("%s%c",block,&split);
for(int j = 0;block[j] != '\0';j++)
{
if(block[j]>='A' && block[j]<='Z'){
block[j] -= ('A'-'a');
}
}
level/=2;
e[i].index = i;
e[i].level = level;
e[i].name = block;
if(split == ' '){
scanf("%s%*c",block);
e[i].id = block;
}
while(!s.empty() && s.top().level>=e[i].level) {
s.pop();
}
if(level == 0){
e[i].parent = -1;
}else{
e[i].parent = s.top().index;
}
s.push(e[i]);
}
while(m--)
{
vector<string> v;
split = ' ';
while(split != '\n'){
scanf("%s%c",block,&split);
if(block[0] != '#'){
for(int j = 0;block[j] != '\0';j++)
{
if(block[j]>='A' && block[j]<='Z'){
block[j] -= ('A'-'a');
}
}
}
v.insert(v.begin(),block);
}
vector<int> res;
for(int i = n-1;i>=0;i--)
{
if(find(i,v)){
res.insert(res.begin(),i+1);
}
}
printf("%d ",res.size());
for(int i = 0;i<res.size();i++)
{
printf("%d ",res[i]);
}
printf("\n");
}
return 0;
}