[csp-201809-3]元素选择器-编译原理
声明:同样是参考照抄hyh学长的代码!(有问题我马上删这篇emm
题目链接:http://118.190.20.162/view.page?gpid=T77
题面:
这棵树的样子(同样是来自学长的图)
题解:
要解决的两个关键问题:
第一个是语义解析,也就是把树构造出来。这个也是用指针实现。这个树的构建比起上一题来更简单,因为节点实际上都是一样的,而上一题(JSON查询)则要分为对象和字符串两种。
这里要注意parent的指向,用一个堆实现查找parent。
第二个是查询。要查询符合条件的路径。这里稍微需要一些思路。
如果直接从上往下找,那这个复杂度最坏的情况是n^2的。但是在实际情况中(也是题目给的提示),从后往前找会大大减少情况(可以排除很多情况)。
处理细节很重要呀!同样也要想清楚每个函数的作用!
#include<bits/stdc++.h>
using namespace std; struct tree
{
int id, dots;
string tag, name;
tree* parent; tree(int id, int dots, string tag, string name): id(id), dots(dots), tag(tag), name(name) ,parent() {}//parent的初始化
}; void split(const string &str, vector<string> &out)
{
string last;
last.clear();
for (int i = ; i < str.size(); i++)
{
if(str[i] == ' ')
{
out.push_back(last);
last.clear();
}
else last+=str[i];
}
out.push_back(last);
} bool equal_ignore_case(const string &a,const string &b)
{
if(a.size() != b.size()) return ;
for(int i = ; i < a.size(); i++)
{
if(tolower(a[i]) != tolower(b[i])) return ;
}
return ;
} bool apply(string str, tree *t)
{
if(str[] == '#') return str == t->name;
else return equal_ignore_case(str, t->tag);
} int main()
{
// freopen("a.in","r",stdin);
int n,m;
string line;
scanf("%d%d",&n,&m); getline(cin,line); vector<tree *> nodes;
stack<tree *> sta; for(int i = ; i <= n; i++)
{
getline(cin, line); int dots=;
while (line[dots] == '.') dots++; string tag, name;
stringstream ss(line.substr(dots));
ss >> tag >> name; tree *now = new tree(i, dots, tag, name);
if(!sta.empty())
{
tree* top;
while (top = sta.top(), top->dots >= dots)
sta.pop();
now->parent = top;
}
sta.push(now);
nodes.push_back(now);
}
/*
for(int i = 0; i < nodes.size(); i++)
{
printf("id = %d dots = %d ",nodes[i]->id,nodes[i]->dots);
cout << "tag = " << nodes[i]->tag << " name = " << nodes[i]->name ;
if(nodes[i]->parent) cout << " parent = " << nodes[i]->parent->id << endl;
else cout << endl;
}
*/
vector<string> selector;
vector<int> ans;
ans.clear();
while (m--)
{
getline(cin, line);
selector.clear();
split(line, selector);
// printf("************* m = %d\n",m);
// for(int i = 0 ; i < selector.size(); i++)
// cout << selector[i] << endl;
ans.clear();
for (int i = ; i < nodes.size(); i++)
{
if (apply(selector.back(),nodes[i]))
{
tree *t = nodes[i];
int sl = selector.size()-;
while(t && sl>=)
{
if(apply(selector[sl],t)) sl--;
t = t->parent; }
if (sl == -)
ans.push_back(nodes[i]->id);
}
}
printf("%d ",ans.size());
for (int i = ; i < ans.size() ; i++)
printf("%d ",ans[i]);
printf("\n");
} return ;
}
更新一下代码(刷题的时候又遇到了这题,重新做了一遍(并没有什么区别..写码习惯不同))
#include<bits/stdc++.h>
using namespace std; struct tree{
string tag,name;
int dots;
tree* parent; tree(int dots, string tag, string name): dots(dots),tag(tag),name(name),parent() {}
}; bool check(const string &s,tree* t)
{
if(s[]=='#') return s == t->name;
else
{
if(s.size()!=t->tag.size()) return ;
for(int i=;i<s.size();i++)
{
if(tolower(s[i])!=tolower(t->tag[i])) return ;
}
return ;
}
} void divide(const string &s,vector<string> &vec)
{
string token;
token.clear();
vec.clear();
for(int i=;i<s.size();i++)
{
if(s[i]==' ')
{
vec.push_back(token);
token.clear();
}
else token+=s[i];
}
vec.push_back(token);
} int main()
{
//freopen("a.in","r",stdin);
int n,m;
scanf("%d%d",&n,&m);
string line;
getline(cin,line); vector<tree* > nodes;
nodes.clear();
stack<tree* > sta;
while(!sta.empty()) sta.pop(); for(int i=;i<=n;i++)
{
getline(cin,line); int dots=;
while(line[dots]=='.') dots++; string tag,name;
stringstream ss(line.substr(dots));
ss >> tag >> name; tree* now = new tree(dots, tag, name); if(!sta.empty())
{
tree* top;
while( top = sta.top() , top->dots >= dots )
sta.pop();
now->parent = top;
}
sta.push(now);
nodes.push_back(now);
} // for(int i=0;i<nodes.size();i++)
// {
// cout << "id = " << i << " tag = " << nodes[i]->tag << " name = " << nodes[i]->name ;
// if(nodes[i]->parent) cout<< " parent = " << nodes[i]->parent->tag;
// cout << endl;
// } vector<string> sel;
vector<int> ans; while(m--)
{
getline(cin,line);
divide(line,sel); ans.clear(); for(int i=;i<nodes.size();i++)
{
int sl=sel.size()-;
if(check(sel[sl],nodes[i]))
{
tree* t=nodes[i]->parent;
sl--;
while(t && sl>=)
{
if(check(sel[sl],t)) sl--;
t=t->parent;
}
if(sl==-) ans.push_back(i+);
}
}
printf("%d ",ans.size());
for(int i=;i<ans.size();i++) printf("%d ",ans[i]);printf("\n");
}
return ;
}
[csp-201809-3]元素选择器-编译原理的更多相关文章
- 跟vczh看实例学编译原理——一:Tinymoe的设计哲学
自从<序>胡扯了快一个月之后,终于迎来了正片.之所以系列文章叫<看实例学编译原理>,是因为整个系列会通过带大家一步一步实现Tinymoe的过程,来介绍编译原理的一些知识点. 但 ...
- 编译原理-词法分析04-NFA & 代码实现
编译原理-词法分析04-NFA & 代码实现 0.术语 NFA 非确定性有穷自动机nondeterministic finite automation. ε-转换ε-transition 是无 ...
- CSS中模拟父元素选择器
很多情况下,我们需要找到父元素,但可惜的是css中并没有这样的一个选择器. 至于原因可以看张鑫旭的如何在CSS中实现父选择器效果这篇文章. 简单来说这个实现并不是真正的父元素选择器,只是利用其它思路来 ...
- Compiler Theory(编译原理)、词法/语法/AST/中间代码优化在Webshell检测上的应用
catalog . 引论 . 构建一个编译器的相关科学 . 程序设计语言基础 . 一个简单的语法制导翻译器 . 简单表达式的翻译器(源代码示例) . 词法分析 . 生成中间代码 . 词法分析器的实现 ...
- 【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集
近来复习编译原理,语法分析中的自上而下LL(1)分析法,需要构造求出一个文法的FIRST和FOLLOW集,然后构造分析表,利用分析表+一个栈来做自上而下的语法分析(递归下降/预测分析),可是这个FIR ...
- 学了编译原理能否用 Java 写一个编译器或解释器?
16 个回答 默认排序 RednaxelaFX JavaScript.编译原理.编程 等 7 个话题的优秀回答者 282 人赞同了该回答 能.我一开始学编译原理的时候就是用Java写了好多小编译器和 ...
- 第二章 Javac编译原理
注:本文主要记录自<深入分析java web技术内幕>"第四章 javac编译原理" 1.javac作用 将*.java源代码文件转化为*.class文件 2.编译流程 ...
- 编译原理(六)自底向上分析之LR分析法
自底向上分析之LR分析法 说明:以老师PPT为标准,借鉴部分教材内容,AlvinZH学习笔记. 基本概念 1. LR分析:从左到右扫描(L)自底向上进行规约(R),是规范规约,也即最右推导(规范推导) ...
- 《编译原理》-用例题理解-自顶向下语法分析及 FIRST,FOLLOW,SELECT集,LL(1)文法
<编译原理>-用例题理解-自顶向下语法分析及 FIRST,FOLLOW,SELECT集,LL(1)文法 此编译原理确定某高级程序设计语言编译原理,理论基础,学习笔记 本笔记是对教材< ...
随机推荐
- 03_Java基础语法_第3天(Scanner、Random、流程控制语句)_讲义
今日内容介绍 1.引用类型变量的创建及使用 2.流程控制语句之选择语句 3.流程控制语句之循环语句 4.循环高级 01创建引用类型变量公式 * A: 创建引用类型变量公式 * a: 我们要学的Scan ...
- erlang随机排列数组
参考karl's answer 1> L = lists:seq(1,10). [1,2,3,4,5,6,7,8,9,10] Associate a random number R with e ...
- mac python install zlib not available
用brew install 3.4.4(python)时报 zipimport.ZipImportError: can't decompress data; zlib not available 的错 ...
- (windows下的)Apache无法启动解决 the requested operation has failed
以下文章是转载别人的,这里只做学习用 ============================================================================== ...
- 转载-C++ vector 用法
转自:http://www.cnblogs.com/wang7/archive/2012/04/27/2474138.html 在c++中,vector是一个十分有用的容器,下面对这个容器做一下总结. ...
- 【操作系统、UNIX环境编程】进程间通信
多个进程可以共享系统中的各种资源,但其中许多资源一次只能为一个进程使用,我们把一次仅允许一个进程使用的资源称为临界资源,许多物理设备都属于临界资源,如打印机等. Linux下进程间通信有如下几种方式: ...
- Android四大组件之Intent(续)
- Java Servlet异步处理、非阻塞I/O和文件上传
异步处理 应用服务器中的 web容器通常对各个客户端情求分别使用一个服务器线程.在工作负载很繁重的情况下,容器常要大量线程来为所有客户端请求服务.可扩展性限制包括内存用尽,或容器线程池耗尽.为了创建可 ...
- 【JavaScript&jQuery】省市区三级联动
HTML: <%@page import="com.mysql.jdbc.Connection"%> <%@ page language="java&q ...
- TCP的拥塞控制 (二)
TCP Reno TCP Reno引入了ssthresh(Slow Start threshold)变量,作为TCP的Slow Start和Congestion Avoidance两个阶段的分界线. ...