CSP 201809-3元素选择器

CSP 201809-3元素选择器

这里是引用在这里插入图片描述在这里插入图片描述在这里插入图片描述

题意:
模拟元素选择。

分析:
id选择器和标签选择器的查询都比较简单,稍微麻烦的是后代选择器。
我用了二维数组保存每个元素的祖先,第一维代表的是层级(冒号的个数除以2),第二维代表的是序号。
多级的后代选择器在匹配时,可以采用贪心的策略:除最后一级外,前面的部分都可以尽量匹配层级小的元素。

代码如下:

#include<iostream>
#include<sstream>
#include<algorithm>
#include<string>
#include<cstring>
#include<iomanip>
#include<vector>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<map>
#define mem(a,b) memset(a,b,sizeof(a))
#define e 2.71828182
#define Pi 3.141592654
using namespace std;

struct node
{
	vector<string> ance_lab[101];//标签祖先(父代) 
	vector<string> ance_id[101];//id祖先 (父代) 
	int col;//冒号个数 
	string label;//标签
	string id;//id属性 
}ele[101];//元素 

bool islegal(string a, string b)//两个标签是否相等(大小写不敏感) 
{
	if (a.length() != b.length()) return false;
	for (int i = 0; i < a.length(); i++)
		if (a[i] == b[i]) continue;
		else if (a[i] == b[i] + 'A' - 'a') continue;
		else if (b[i] == a[i] + 'A' - 'a') continue;
		else return false;
	return true;
}

int main()
{
	int n, m;
	cin >> n >> m;
	getchar();
	for (int i = 1; i <= n; i++)
	{
		string str;
		getline(cin, str);

		int num = str.find('.');
		while (str[num] == '.' || num == -1) num++;
		ele[i].col = num;//冒号个数 

		if (str.find('#') != string::npos)//有id属性 
		{
			ele[i].id = str.substr(str.find('#') + 1);
			ele[i].label = str.substr(num, str.find('#') - num - 1);
		}
		else //无id属性 
		{
			ele[i].id = "";
			ele[i].label = str.substr(num);
		}

		//找祖先 
		for (int j = 1; j < i; j++)
		{
			if (ele[j].col >= num) continue;
			int cnt = ele[j].col / 2;
			if (ele[j].id != "")  ele[i].ance_id[cnt].push_back(ele[j].id);
			ele[i].ance_lab[cnt].push_back(ele[j].label);

		}
	}


	for (int i = 1; i <= m; i++)
	{
		string sel;//selector
		getline(cin, sel);
		int ans = 0, a[101];//查询结果 
		mem(a, 0);
		if (sel.find('#') == string::npos && sel.find(' ') == string::npos)//标签选择器查询 
		{
			for (int j = 1; j <= n; j++)
				if (islegal(sel, ele[j].label))
					a[++ans] = j;
			cout << ans << ' ';
			for (int k = 1; k <= ans; k++) cout << a[k] << ' ';
			cout << endl;
		}

		else if (sel.find('#') != string::npos && sel.find(' ') == string::npos)//id选择器查询
		{
			sel = sel.substr(1);//去掉井号 
			for (int j = 1; j <= n; j++)
				if (sel == ele[j].id)
					a[++ans] = j;
			cout << ans << ' ';
			for (int k = 1; k <= ans; k++) cout << a[k] << ' ';
			cout << endl;
		}

		else //后代选择器 
		{
			string str;
			for (int j = 1; j <= n; j++)
			{
				//利用字符串流和栈将后代选择器的子代和父代按顺序区分出来 
				stringstream ss(sel);
				stack<string> temp;
				int cnt = 0;//子代和父代的总数 
				while (ss >> str)
				{
					temp.push(str);
					cnt++;
				}
				//子代是否满足条件 
				str = temp.top(); temp.pop();
				if (str.find('#') == string::npos && !islegal(str, ele[j].label)) continue;
				else if (str.find('#') != string::npos && str.substr(1) != ele[j].id) continue;
				//父代是否满足条件 
				int sum = 0;//找到的父代个数 
				for (int p = (ele[j].col - 2) / 2; p >= 0; p--)
				{
					str = temp.top();
					if (str.find('#') == string::npos) //标签 
						for (int q = 0; q < ele[j].ance_lab[p].size(); q++)
						{
							if (islegal(str, ele[j].ance_lab[p][q]))
							{
								sum++;
								temp.pop();
								break;
							}
						}
					else //id
						for (int q = 0; q < ele[j].ance_id[p].size(); q++)
						{
							string stri = str.substr(1);//没讲#保存在id里,记得要将#去掉 
							if (stri == ele[j].ance_id[p][q])
							{
								sum++;
								temp.pop();
								break;
							}
						}
					if (sum == cnt - 1)
					{
						a[++ans] = j;
						break;
					}
				}
			}
			cout << ans << ' ';
			for (int k = 1; k <= ans; k++) cout << a[k] << ' ';
			cout << endl;
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值