CSP 201809-3 元素选择器

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

思路

大体思路是将文档转换为树结构,这里的树结构使用的是类似于并查集的方式,使用一维数组实现,将需要查询的元素一层一层向上查找。基本思路不难,但是其中的细节很多,写起来比较麻烦,下面就一点一点来说明过程。
先来说明数组等静态变量:
map<string,vector mp : 将元素与位置(行号)相映射
map<int,int> levelLast : 记录层次为level的上一行是哪一行,是为了便于得到父节点
vector<string> str : 查询元素
vector<int> ans : 结果
node line[] : 存储文档,建立树结构

第一部分是读入文档,处理文档,建树

设置level值,为了便于得到这一行的父节点是哪一行,直接 levelLast[level-1]就得到了父节点的行号

		int level=index/2;
		line[i].level=level;
		line[i].parent=levelLast[level-1];
		if(i==1){
			levelLast[-1]=0;
			levelLast[0]=1;
		} 
		else levelLast[level]=i;

设置tag,将tag转为小写

		while(index<tmp.size() && tmp[index]!=' '){
			if(tmp[index]>='A' && tmp[index]<='Z') tmp[index]+=32;
			index++;	
		} 

判断有没有id,有的话同时设置id

		if(index==tmp.size()) {//only have tag
			line[i].tag=tmp.substr(level*2,index-level*2);
			mp[line[i].tag].push_back(i);
		}
		else {
			line[i].tag=tmp.substr(level*2,index-level*2);
			line[i].id=tmp.substr(index+1,tmp.size()-index);
			mp[line[i].tag].push_back(i); 
			mp[line[i].id].push_back(i);
		}

第二部分,读入查询元素
由于一行可能有多个查询元素,需要用空格进行切分,我这里遍历去除空格,相当于java 的split方法

		while(true){
			last=index;
			while(index<tmp.size() && tmp[index]!=' '){
				if(flg && tmp[index]>='A' && tmp[index]<='Z') tmp[index]+=32;
				index++;
			}
			str.push_back(tmp.substr(last,index-last));
			index++;
			if(index>=tmp.size()){
				break;
			}
		}

但是这么麻烦,肯定有更简单的方法
C语言的strtok
C++的stringstream
stringstream和getline一起使用

接下来就自下而上来寻找与匹配

bool judge(int j){//str.size() >= 2
	int parent=line[j].parent  ;
	for(int i=str.size()-2;i>=0;i--){//从str倒数第二个 开始向上比较 
//		cout<<"str[i]:"<<str[i]<<"  line[parent].tag:"<<line[parent].tag<<"  line[parent].id:"<<line[parent].id<<endl;
		if(line[parent].tag!=str[i] && line[parent].id!=str[i]) return false;
		parent=line[parent].parent;
		if(parent==0) return false;
	}
	return true;
}

最后顺序可能不对,排个序
细节很多,中间还犯了一个很迷的错误,我就换了种方式来写

代码

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;

struct node{
	string tag,id;
	int parent,level;
	node(){tag.clear();id.clear();parent=-1;level=-1;}
	void show(){
		printf("tag:%-10s id:%-10s parent:%2d level:%2d\n",tag.c_str(),id.c_str(),parent,level);
//		cout<<"tag:"<<tag<<"   id="<<id<<"   parent:"<<parent<<"  level:"<<level<<endl;
	}
};
map<string,vector<int>> mp;
map<int,int> levelLast;
vector<string> str;
vector<int> ans;
int n,m,parent,last,index;
node line[105];
string tmp;

bool judge(int j){//str.size() >= 2
	int parent=line[j].parent  ;
	for(int i=str.size()-2;i>=0;i--){//从str倒数第二个 开始向上比较 
//		cout<<"str[i]:"<<str[i]<<"  line[parent].tag:"<<line[parent].tag<<"  line[parent].id:"<<line[parent].id<<endl;
		if(line[parent].tag!=str[i] && line[parent].id!=str[i]) return false;
		parent=line[parent].parent;
		if(parent==0) return false;
	}
	return true;
}


int main(){
	scanf("%d %d",&n,&m);getchar();
	levelLast[-1]=0;
	for(int i=1;i<=n;i++){
		getline(cin,tmp);
		index=0;
		while(tmp[index]=='.') index++;
		
		int level=index/2;
		line[i].level=level;
		line[i].parent=levelLast[level-1];
		if(i==1){
			levelLast[-1]=0;
			levelLast[0]=1;
		} 
		else levelLast[level]=i;
		
		
		
		//tag
		while(index<tmp.size() && tmp[index]!=' '){
			if(tmp[index]>='A' && tmp[index]<='Z') tmp[index]+=32;
			index++;	
		} 
		
		if(index==tmp.size()) {//only have tag
			line[i].tag=tmp.substr(level*2,index-level*2);
			mp[line[i].tag].push_back(i);
		}
		else {
			line[i].tag=tmp.substr(level*2,index-level*2);
			line[i].id=tmp.substr(index+1,tmp.size()-index);
			mp[line[i].tag].push_back(i); 
			mp[line[i].id].push_back(i);
		}
	}
//	for(map<string,vector<int>>::iterator it=mp.begin();it!=mp.end();it++){
//		cout<<it->first<<" , ";
//		for(int i:it->second){
//			cout<<i<<" ";
//		}
//		cout<<endl;
//	}
//	cout<<endl<<"************************"<<endl;
//	for(int i=1;i<=n;i++){
//		line[i].show();
//	}
//	cout<<"**********************"<<endl<<endl;
	for(int i=1;i<=m;i++){
		getline(cin,tmp);
		last=0;index=0;
		str.clear();
		bool flg=true;//istoLower
		if(tmp[0]=='#') flg=false;
		while(true){
			last=index;
			while(index<tmp.size() && tmp[index]!=' '){
				if(flg && tmp[index]>='A' && tmp[index]<='Z') tmp[index]+=32;
				index++;
			}
			str.push_back(tmp.substr(last,index-last));
			index++;
			if(index>=tmp.size()){
				break;
			}
		}
		ans.clear();
		if(str.size()==1){
			ans=mp[str.front()];
		}
		else{//str.size>=2
			for(int j : mp[str.back()] ){
				if(judge(j)) ans.push_back(j);
			}
		}
		sort(ans.begin(),ans.end());
		printf("%d",ans.size());
		for(int j:ans)
			printf(" %d",j);
		printf("\n");
		
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值