思路
大体思路是将文档转换为树结构,这里的树结构使用的是类似于并查集的方式,使用一维数组实现,将需要查询的元素一层一层向上查找。基本思路不难,但是其中的细节很多,写起来比较麻烦,下面就一点一点来说明过程。
先来说明数组等静态变量:
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;
}