csp20180903-元素选择器

题目

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

思路

  • 原思路是建立一棵树,然后如果要进行匹配,就从根节点开始查找,但是可能复杂度比较高,因为这个的多级的后代选择器在匹配时,会比较麻烦。
  • 后来参考了一下网上是思路,发现更简单、快速。
  • 先进行n行输入,把每一行都输入进node类型的数组nd,包括lable、id、nb等信息,lable是标签,nb是记录的此行共有几个点,也就是级别。
  • 如果搜索的时候,只给出了一级,那么只要遍历数组nd,寻找有没有匹配的lable或者id即可。
  • 若是多级别搜索,那么只要判断最低级别的p,先找到它,然后对它高的等级的id/标签的map数组an相应的值+1。最后再判断,看所有比p高等级的id/标签的an的值是否足够大(也就是看遍历的次数是否足够)。

注意点

  • 这里使用了字符串分割函数strtok();

1、函数的作用是分解字符串,所谓分解,即没有生成新串,只是在s所指向的内容首次出现分界符的位置,将分界符修改成了’/0’,故第一次用strtok()返回第一个子串
2、第一次提取子串完毕之后,继续对源字符串s进行提取,应在其后(第二次,第三次。。。第n次)的调用中将strtok的第一个参数赋为空值NULL(表示函数继续从上 一次调用隐式保存的位置,继续分解字符串;对于前一次次调用来说,第一次调用结束前用一个this指针指向了分界符的下一位)
3、当this指针指向“\0” 时,即没有被分割的子串了,此时则返回NULL
4、可以把delim理解为分隔符的集合,delim中的字符均可以作为分隔符。
5、strtok在调用的时候,如果起始位置即为分隔符,则忽略了起始位置开始的分隔符

demand.clear();
	char *p=strtok(s," ");
	while(p){
		demand.push_back(p);
		p=strtok(NULL," "); 
	}

这里是对s进行分割,以“ ”为分隔符。第一次使用是第一个变量是s(待分割的字符串),后面的第一个变量都是“NULL”。

代码

#include<iostream>
#include<map>
#include<cstring>
#include<vector>
#include<ctype.h>
#include<string>
#include <string.h>
using namespace std;

struct node{
	string lable,id;//标签和id 
	int nb;//前面点的个数 
}nd[110]; 

//大写转换成小写 
string change(string s){
	for(int i=0;i<s.size() ;i++){
		if(s[i]>='A'&&s[i]<='Z'){
			s[i]=s[i]+'a'-'A';
		}
	}
	return s;
} 

map<string,int>an,query;//an表示各个祖先含有的标签,id属性等,query表示要查询的 
vector<string>demand;

//以空格进行分割字符串s,以空格为间隔的字符串都入demand数组中 
void split(char* s){
	
    demand.clear();
	char *p=strtok(s," ");
	while(p){
		demand.push_back(p);
		p=strtok(NULL," "); 
	}
}

int main(){
	int n,m;
	scanf("%d%d",&n,&m);//n为结构化文档的行数,m为查询次数
	getchar();//为getline读取回车 
	
	for(int i=1;i<=n;i++){//此部分为将数据存到数组nd里面 
		string str;getline(cin,str); 
		
		//先找出....的个数 
		int cnt=0;
		for(int j=0;j<str.size();j++) {
			if(str[j]=='.')cnt++;//....的个数 
			else break;
		}
		nd[i].nb=cnt;	//0-(cnt-1)是...的位置
	
		//接下来是标记部分,
		int len=0; 
		int pos=-1;//记录了id从pos开始,如果有id的话 
		for(int j=cnt;j<str.size() ;j++,len++){
			if(str[j]==' '){
			    if(j+1<str.size()&&str[j+1]=='#')
		  	    pos=j+1;
		  	    break;
			}
		}
		
		//label记录标签,是s的cnt到len 	
	    nd[i].lable=str.substr(cnt,len);
		nd[i].lable=change(nd[i].lable);	//由于标签的匹配大小写不敏感,因此化为小写 
		
		if(pos==-1)//如果没有id属性,就让id="" 
		  nd[i].id="";//id
		else
		  nd[i].id=str.substr(pos);//pos及以后都是id 
		  		
	} 
	
	
	//查询操作 
	while(m--){
		//getchar();//为getline读取回车 
	    char d[100];
		gets(d); 
		split(d);//以空格进行分割字符串s,以空格为间隔的字符串都入demand数组中 
		
		vector<int>ans;
		if(demand.size() ==1){//demand中只有一条指令 
			string ss=demand[0];
			if(ss[0]!='#')//查询标签大小写不敏感
			  ss=change(ss);//化为小写  
			//进行匹配
			for(int i=1;i<=n;i++)
			  if(ss==nd[i].lable||ss==nd[i].id)
			    ans.push_back(i); //保存行号 
		}	
		
		else{
			query.clear();
			
			for(int i=0;i<demand.size()-1 ;i++){
				if(demand[i][0]!='#'){//标签转小写 
					demand[i]=change(demand[i]);
				}
				query[demand[i]]++;//用query来记录标签/id 
			}
			
			string q=demand.back() ;
			if(q[0]!='#')//查询标签大小写不敏感
			  q=change(q);//化为小写 
			  
			for(int i=1;i<=n;i++){//遍历整个nd数组 
			
			   
				if(q==nd[i].lable||q==nd[i].id){//最后面的q可以匹配 
					an.clear();
				    for(int j=i-1;j>0&&nd[j].nb<=nd[i].nb;j--){//从第i-1行往上遍历,直到第j行的级别比i要高 
                        if(nd[j].nb==nd[i].nb)continue;//关键:细节
				  	    an[nd[j].lable]++;//由于标签不会为空,因此直接加一 
				  	    if(nd[j].id!="")//只将不为空的id进行加一 
				  	      an[nd[j].id]++;
				    }
				    
				    bool flag=true;
				    //遍历查询的所有id选择器和标签选择器 ,判断i是否合适 
			        for(map<string,int>::iterator it=query.begin();it!=query.end();it++)
				        if(an.count(it->first)==0||an[it->first]<it->second){//如果i的祖先没有或者有但是个数不够 
				  	        flag=false;
				  	        break;
				        }
				    if(flag)
				        ans.push_back(i); 
			    } 			 
		    }
		    
		    
	    }
		printf("%d",ans.size());
		for(int i=0;i<ans.size();i++)
		printf(" %d",ans[i]);
		printf("\n");
	} 
	return 0; 
	
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值