[csp-201809-3]元素选择器-编译原理
声明:同样是参考照抄hyh学长的代码!(有问题我马上删这篇emm
题目链接:http://118.190.20.162/view.page?gpid=T77
题面:
这棵树的样子(同样是来自学长的图)
题解:
要解决的两个关键问题:
第一个是语义解析,也就是把树构造出来。这个也是用指针实现。这个树的构建比起上一题来更简单,因为节点实际上都是一样的,而上一题(JSON查询)则要分为对象和字符串两种。
这里要注意parent的指向,用一个堆实现查找parent。
第二个是查询。要查询符合条件的路径。这里稍微需要一些思路。
如果直接从上往下找,那这个复杂度最坏的情况是n^2的。但是在实际情况中(也是题目给的提示),从后往前找会大大减少情况(可以排除很多情况)。
处理细节很重要呀!同样也要想清楚每个函数的作用!
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 struct tree 5 { 6 int id, dots; 7 string tag, name; 8 tree* parent; 9 10 tree(int id, int dots, string tag, string name): id(id), dots(dots), tag(tag), name(name) ,parent(0) {}//parent的初始化 11 }; 12 13 void split(const string &str, vector<string> &out) 14 { 15 string last; 16 last.clear(); 17 for (int i = 0; i < str.size(); i++) 18 { 19 if(str[i] == ' ') 20 { 21 out.push_back(last); 22 last.clear(); 23 } 24 else last+=str[i]; 25 } 26 out.push_back(last); 27 } 28 29 bool equal_ignore_case(const string &a,const string &b) 30 { 31 if(a.size() != b.size()) return 0; 32 for(int i = 0; i < a.size(); i++) 33 { 34 if(tolower(a[i]) != tolower(b[i])) return 0; 35 } 36 return 1; 37 } 38 39 bool apply(string str, tree *t) 40 { 41 if(str[0] == '#') return str == t->name; 42 else return equal_ignore_case(str, t->tag); 43 } 44 45 int main() 46 { 47 // freopen("a.in","r",stdin); 48 int n,m; 49 string line; 50 scanf("%d%d",&n,&m); 51 52 getline(cin,line); 53 54 vector<tree *> nodes; 55 stack<tree *> sta; 56 57 for(int i = 1; i <= n; i++) 58 { 59 getline(cin, line); 60 61 int dots=0; 62 while (line[dots] == '.') dots++; 63 64 string tag, name; 65 stringstream ss(line.substr(dots)); 66 ss >> tag >> name; 67 68 tree *now = new tree(i, dots, tag, name); 69 if(!sta.empty()) 70 { 71 tree* top; 72 while (top = sta.top(), top->dots >= dots) 73 sta.pop(); 74 now->parent = top; 75 } 76 sta.push(now); 77 nodes.push_back(now); 78 } 79 /* 80 for(int i = 0; i < nodes.size(); i++) 81 { 82 printf("id = %d dots = %d ",nodes[i]->id,nodes[i]->dots); 83 cout << "tag = " << nodes[i]->tag << " name = " << nodes[i]->name ; 84 if(nodes[i]->parent) cout << " parent = " << nodes[i]->parent->id << endl; 85 else cout << endl; 86 } 87 */ 88 vector<string> selector; 89 vector<int> ans; 90 ans.clear(); 91 while (m--) 92 { 93 getline(cin, line); 94 selector.clear(); 95 split(line, selector); 96 // printf("************* m = %d\n",m); 97 // for(int i = 0 ; i < selector.size(); i++) 98 // cout << selector[i] << endl; 99 ans.clear(); 100 for (int i = 0; i < nodes.size(); i++) 101 { 102 if (apply(selector.back(),nodes[i])) 103 { 104 tree *t = nodes[i]; 105 int sl = selector.size()-1; 106 while(t && sl>=0) 107 { 108 if(apply(selector[sl],t)) sl--; 109 t = t->parent; 110 111 } 112 if (sl == -1) 113 ans.push_back(nodes[i]->id); 114 } 115 } 116 printf("%d ",ans.size()); 117 for (int i = 0; i < ans.size() ; i++) 118 printf("%d ",ans[i]); 119 printf("\n"); 120 } 121 122 return 0; 123 }
更新一下代码(刷题的时候又遇到了这题,重新做了一遍(并没有什么区别..写码习惯不同))
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 struct tree{ 5 string tag,name; 6 int dots; 7 tree* parent; 8 9 tree(int dots, string tag, string name): dots(dots),tag(tag),name(name),parent(0) {} 10 }; 11 12 bool check(const string &s,tree* t) 13 { 14 if(s[0]=='#') return s == t->name; 15 else 16 { 17 if(s.size()!=t->tag.size()) return 0; 18 for(int i=0;i<s.size();i++) 19 { 20 if(tolower(s[i])!=tolower(t->tag[i])) return 0; 21 } 22 return 1; 23 } 24 } 25 26 void divide(const string &s,vector<string> &vec) 27 { 28 string token; 29 token.clear(); 30 vec.clear(); 31 for(int i=0;i<s.size();i++) 32 { 33 if(s[i]==' ') 34 { 35 vec.push_back(token); 36 token.clear(); 37 } 38 else token+=s[i]; 39 } 40 vec.push_back(token); 41 } 42 43 int main() 44 { 45 //freopen("a.in","r",stdin); 46 int n,m; 47 scanf("%d%d",&n,&m); 48 string line; 49 getline(cin,line); 50 51 vector<tree* > nodes; 52 nodes.clear(); 53 stack<tree* > sta; 54 while(!sta.empty()) sta.pop(); 55 56 for(int i=1;i<=n;i++) 57 { 58 getline(cin,line); 59 60 int dots=0; 61 while(line[dots]=='.') dots++; 62 63 string tag,name; 64 stringstream ss(line.substr(dots)); 65 ss >> tag >> name; 66 67 tree* now = new tree(dots, tag, name); 68 69 if(!sta.empty()) 70 { 71 tree* top; 72 while( top = sta.top() , top->dots >= dots ) 73 sta.pop(); 74 now->parent = top; 75 } 76 sta.push(now); 77 nodes.push_back(now); 78 } 79 80 // for(int i=0;i<nodes.size();i++) 81 // { 82 // cout << "id = " << i << " tag = " << nodes[i]->tag << " name = " << nodes[i]->name ; 83 // if(nodes[i]->parent) cout<< " parent = " << nodes[i]->parent->tag; 84 // cout << endl; 85 // } 86 87 vector<string> sel; 88 vector<int> ans; 89 90 while(m--) 91 { 92 getline(cin,line); 93 divide(line,sel); 94 95 ans.clear(); 96 97 for(int i=0;i<nodes.size();i++) 98 { 99 int sl=sel.size()-1; 100 if(check(sel[sl],nodes[i])) 101 { 102 tree* t=nodes[i]->parent; 103 sl--; 104 while(t && sl>=0) 105 { 106 if(check(sel[sl],t)) sl--; 107 t=t->parent; 108 } 109 if(sl==-1) ans.push_back(i+1); 110 } 111 } 112 printf("%d ",ans.size()); 113 for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);printf("\n"); 114 } 115 return 0; 116 }