CCF201809-3
我的程序
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
typedef struct TreeNode {
string label;
string id;
int LineNum;
int DotNum;
struct TreeNode* child;
struct TreeNode* bother;
struct TreeNode* father;
TreeNode() { //结构体初始化
this->label = "";
this->id = "";
this->LineNum = 0;
this->DotNum = -1;
this->father = NULL;
this->bother = NULL;
this->child = NULL;
}
}TreeNode, * TreeNodePointer;
class solution {
private:
TreeNodePointer root;
TreeNodePointer recent;
public:
solution() {
root = new TreeNode;
recent = root;
}
void Insert(TreeNodePointer t) { //由上一个插入节点向上回溯,避免匹配错误
TreeNodePointer p = recent;
if (t->DotNum > p->DotNum) {
p->child = t;
}
else if (t->DotNum == p->DotNum) {
p->bother = t;
}
else {
while (p->DotNum != t->DotNum) {
p = p->father;
}
while (p->bother) { //实际上没有必要,因为在与t相同级数的节点中,该子树节点与t是最后两个
p = p->bother;
}
p->bother = t;
}
t->father = p;
recent = t;
}
static bool CompareLabel(TreeNodePointer t, string SelectItem) {
return t->label == SelectItem;
}
static bool CompareId(TreeNodePointer t, string SelectItem) {
return t->id == SelectItem;
}
void find(bool(*compare)(TreeNodePointer t, string SelectItem), string SelectItem, TreeNodePointer r, vector<int>& ans) {
if (r == NULL)
return;
if (compare(r, SelectItem))
ans.push_back(r->LineNum);
find(compare, SelectItem, r->child, ans);
find(compare, SelectItem, r->bother, ans);
}
vector<int> FindLabel(string SelectItem) {
vector<int> ans;
find(CompareLabel, SelectItem, root, ans);
return ans;
}
vector<int> FindId(string SelectItem) {
vector<int> ans;
find(CompareId, SelectItem, root, ans);
return ans;
}
void FindLast(vector<string>& SelectItems, TreeNodePointer r, vector<int>& ans, int size) {
if (r == NULL)
return;
if (r->id == SelectItems[size - 1] || r->label == SelectItems[size - 1]) {
int flag = size - 2;
TreeNodePointer p = r;
while (p->father) {
p = p->father;
if (p->id == SelectItems[flag] || p->label == SelectItems[flag]) {
flag--;
}
if (flag < 0) {
break;
}
}
if (flag < 0)
ans.push_back(r->LineNum);
}
FindLast(SelectItems, r->child, ans, size);
FindLast(SelectItems, r->bother, ans, size);
}
vector<int> MultipleFind(vector<string>& SelectItems) {
vector<int> ans;
FindLast(SelectItems, root, ans, SelectItems.size());
return ans;
}
};
void func() {
solution tree;
int m, n;
cin >> n >> m;
char c = getchar(); //消除换行符
for (int i = 1;i <= n;i++) { //构建结构树
string label, id, line;
int DotNum = 0;
getline(cin, line);
int j = 0;
while (line[j] == '.') { //计算小数点
j++;
DotNum++;
}
if (DotNum > 0) {
line.erase(0, DotNum);
}
int index = line.find("#"); //分离label和id
if (index != string::npos) {
id = line.substr(index);
label = line.substr(0, index - 1);
}
else {
id = "";
label = line;
}
transform(label.begin(), label.end(), label.begin(), ::tolower); //标签选择器对于大小写不敏感
TreeNodePointer tmp = new TreeNode;
tmp->DotNum = DotNum;
tmp->id = id;
tmp->label = label;
tmp->LineNum = i;
tree.Insert(tmp);
}
string* SelectItems = new string[m]; //选择器查询
for (int i = 0;i < m;i++) {
getline(cin, SelectItems[i]);
}
for (int i = 0;i < m;i++) {
vector<int> ans;
int index = SelectItems[i].find(" ");
if (index != string::npos) { //多重选择器
vector<string> query;
char* sp = strtok((char*)SelectItems[i].c_str(), " ");//将插叙用空格分割,按序存放在query向量中
while (sp)
{
string tmp(sp);
if (tmp[0] != '#') {
transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
}
query.push_back(tmp);
sp = strtok(NULL, " ");
}
ans = tree.MultipleFind(query);
}
else {
if (SelectItems[i][0] == '#') { //id选择器
ans = tree.FindId(SelectItems[i]);
}
else { //标签选择器
ans = tree.FindLabel(SelectItems[i]);
}
}
sort(ans.begin(), ans.end());
cout << ans.size() << " ";
for (int j = 0;j < ans.size();j++) {
cout << ans[j] << " ";
}
cout << endl;
}
}
int main() {
func();
return 0;
}
别人的程序
引用自CCF CSP 真题题解
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
using namespace std;
const int N=105;
struct Node{
string lable,id;//标签和属性
int cnt;//缩进
}a[N];
//将字符串化成小写
void mystrlwr(string &s)
{
for(int i=0;i<s.length();i++)
s[i]=tolower(s[i]);
}
//在数组a中[1,start]寻找缩进小于cnt,且标签或属性等于s的元素
bool search(Node a[],int &start,int &cnt,string s)
{
for(int i=start;i>=1;i--)//遍历
{
if(a[i].cnt<cnt)
{
//查询成功
cnt=a[i].cnt,start=i;//保证a[i]是它的父亲,即第一个缩进小于它的元素
if(s==a[i].lable||s==a[i].id) return true;//成功
}
}
return false;//查询失败
}
int main()
{
int n,m;
string s;
cin>>n>>m;//读入n和m
getchar();//读取换行符
for(int i=1;i<=n;i++)
{
getline(cin,s);
//pos1记录标签的起始位置,pos2记录id属性的起始位置,cnt记录缩进
int pos1=-1,pos2=-1,cnt=0;
for(int j=0;j<s.length();j++)
if(s[j]=='.')
cnt++;
else if(pos1==-1&&s[j]!='#')
pos1=j;
else if(s[j]=='#')
pos2=j;
a[i].cnt=cnt;
if(pos2==-1)//如果不存在id属性
{
a[i].lable=s.substr(pos1);
a[i].id="";//置为空
}
else//存在id属性
{
a[i].lable=s.substr(pos1,pos2-pos1-1);
a[i].id=s.substr(pos2);
}
mystrlwr(a[i].lable);//由于标签属性大小写不敏感,因此统一换成小写
}
for(int i=0;i<m;i++)//读入m个查询
{
char tmp[100];
vector<string>query;//存储查询
vector<int>ans;//存储结果
gets(tmp);//读入
char *sp=strtok(tmp," ");//将插叙用空格分割,按序存放在query向量中
while(sp)
{
query.push_back(sp);
sp=strtok(NULL," ");
}
int len=query.size();
for(int j=0;j<len;j++)//将标签统一化成小写
if(query[j][0]!='#') mystrlwr(query[j]);
for(int j=1;j<=n;j++)//遍历n行元素
{
if(query[len-1]==a[j].id||query[len-1]==a[j].lable)//最后一级选择器匹配了
{
int start=j,cnt=a[j].cnt,k=len-2;//使用search函数匹配各级父选择器
for(;k>=0;k--)
{
if(!search(a,start,cnt,query[k])) break;
}
if(k<0)//成功
ans.push_back(j);
}
}
//输出结果
cout<<ans.size();
for(int j=0;j<ans.size();j++)
cout<<" "<<ans[j];
cout<<endl;
}
return 0;
}