第四道月模csp201809-3 元素选择器

该博客详细介绍了CSP201809第三题——元素选择器的题目背景、解题思路及AC代码。博主通过创建element结构体和使用split函数处理输入,解释了如何处理结构化文档和选择器,特别是后代选择器的匹配方法。同时,强调了解题过程中的注意事项,如容器清理和标签小写化。
摘要由CSDN通过智能技术生成

题目背景

在这里插入图片描述在这里插入图片描述

题目描述

在这里插入图片描述在这里插入图片描述

输入输出

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

在这里插入图片描述

Sample Output

在这里插入图片描述

数据规模和约定

在这里插入图片描述

思路分析

根据题意,创建element结构体,新建element类型数组e[],用来存储结构化文档中的元素。
从主函数入手,实现输入输出。
输入有两部分:结构化文档和选择器。
读入结构化文档时由于有属性会出现空格,所以使用getline函数直接读入一整行的数据,读入后再用split函数进行分割。
split函数切分:首先用一个for循环遍历整个字符串,找到第一个非’ .'元素的位置s1和属性出现的开头位置s2。将flag置为2,表示有属性。然后用substr()函数生成子字符串。
为每一个选择器进行选择:
首先用toLower函数将输入的结构化文档全部转化为小写,便于后面比较。非后代选择器的查找,只要遍历一遍数组,判断其属性是否符合条件,符合则将其行号插入vector中;对于后代选择器,调用match函数,从被选择元素开始往前,与vector中元素一一对照,直到两边有一边元素对照完毕,如果是vector中元素对照完毕则说明满足条件,否则不满足。将满足条件的行号插入vector中。
最后,ans中存储的是每个选择器对应的元素,直接输出大小和元素即可。

注意

1.每次处理完一个选择器之后要清空容器
2.标签小写化

AC代码

#include<bits/stdc++.h>
using namespace std;

int n=0,m=0;
struct element{
	string label;   //标签
	string id;      //属性 
	int level;      //目前元素的层级
}e[110];
vector<string> q;  //查询
vector<int> ans;   

void toLower(string &t)
{  //转为小写字母 
	for(int i=0;i<t.size();i++){
		if(t[i]>'A'-1&&t[i]<'Z'+1){
			t[i]=tolower(t[i]);
		}
	}
} 

void split(string &t,int x){
	int suo=0,flag=0;
	int s1=0,s2=0;
	for(int i=0;i<t.size();i++){
		if(t[i]=='.'){suo++;	}
		if(t[i]!='.'&&flag==0){   //记录遇到的第一个非'.'位置 
			flag=1;	 
			s1=i;
		}
		if(t[i]==' '&&flag==1){   //若有属性,记录属性出现位置
			s2=i+1;	
			flag=2;	
			break; 
		}
	}
	string tmp,tmp_id;
	if(flag!=2){   
	//没有属性,只有标签和缩进 
		tmp=t.substr(s1);
		toLower(tmp);   //改为小写
		e[x].label=tmp;
		e[x].level=suo/2; 
	}
	else{   //有属性 
		tmp=t.substr(s1,s2-s1-1);
		toLower(tmp);   //改为小写
		tmp_id=t.substr(s2);
		e[x].label=tmp;
		e[x].id=tmp_id;
		e[x].level=suo/2; 
	}
} 

bool match(int x){  //判断元素是否与选择器匹配 
	int t=e[x].level,qq=q.size()-2;
	for(int i=x-1;i>=0;i--){
		if(e[i].level==t-1){
			if(q[qq][0]!='#'&&q[qq]==e[i].label){qq--;}
            else if(q[qq][0]=='#'&&q[qq]==e[i].id){qq--;}
            t=e[i].level;
            if(qq<0)return true;
		}
	}
	return false;
}

int main(){
	cin>>n>>m;
	string tmp;
	getchar();   
	for(int i=0;i<n;i++)
	{   //读入结构化文档 
		getline(cin,tmp);
		split(tmp,i);
	} 
	
	for(int i=0;i<m;i++)
	{   //读入选择器 
		getline(cin,tmp);
		stringstream st;
		st<<tmp;
		string tt;
		while(st>>tt){
			if(tt[0]!='#'){toLower(tt);	}   //不是id选择器,大小写不敏感 
			q.push_back(tt);
		}
		int qs=q.size();
		for(int j=0;j<n;j++){
			if(q[qs-1][0]=='#'&&q[qs-1]==e[j].id
			||q[qs-1][0]!='#'&&q[qs-1]==e[j].label){
				if(q.size()==1||match(j)){
					ans.push_back(j+1);
				}
			}
		}
		cout<<ans.size();
		for(int i=0;i<ans.size();i++){
			cout<<" "<<ans[i];
		}
		cout<<"\n";
		ans.clear();
		q.clear();
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值