CCF 202303-3 LDAP题目求助

问题描述

为了简化该问题,我们约定,每个用户的 DN 是一个正整数,且不会重复。有若干种用户的属性,用正整数编号。每个用户可以具有这些属性中的若干个,且每个属性只能有一个值。每个属性的值也是一个正整数。例如,假定有两个用户:用户 1 和用户 2,他们的 DN 分别是 1 和 2。一共有 3 种属性。用户 1 具有属性 1 和属性 2,且属性 1 的值为 2,属性 2 的值为 3;但不具有属性 3。用户 2 具有属性 2 和属性 3,且属性 2 的值为 3,属性 3 的值为 1;但不具有属性 1。如下表所示:

DN属性 1属性 2属性 3
123N/A
2N/A31

一个匹配表达式可以是一个属性的值,也可以是多个匹配表达式的逻辑组合。只匹配一个属性的值的表达式称为原子表达式,原子表达式的形式为 <属性编号><操作符><属性值>。其中操作符有两种:断言与反断言。断言操作符为 :,表示匹配具有该属性且值与之相等的用户;反断言操作符为 ~,表示匹配具有该属性且值与之不等的用户。例如,表达式 1:2 可以与上述用户 1 相匹配,但不能与用户 2 相匹配;而表达式 3~1则不能与任何一个用户相匹配。

表达式可以进行逻辑组合,其语法是:<操作符>(表达式 1)(表达式 2)。其中操作符有两种:与(&)和或(|)。如果操作符为与,则当且仅当两个表达式都与某一用户相匹配时,该表达式与该用户相匹配;如果操作符为或,则当且仅当两个表达式中至少有一个与某一用户相匹配时,该表达式与该用户相匹配。例如,表达式 &(1:2)(2:3) 可以与用户 1 相匹配,但不能与用户 2 相匹配;而表达式 |(1:2)(3:1) 则可以与两个用户都相匹配。

形式化地,上述语法用 BNF 范式表示如下:

NON_ZERO_DIGIT =  "1" / "2" / "3" / "4" / 
                  "5" / "6" / "7" / "8" / "9"
DIGIT          =  "0" / NON_ZERO_DIGIT
NUMBER         =  NON_ZERO_DIGIT / (NON_ZERO_DIGIT DIGIT*)
ATTRIBUTE      =  NUMBER
VALUE          =  NUMBER
OPERATOR       =  ":" / "~"
BASE_EXPR      =  ATTRIBUTE OPERATOR VALUE
LOGIC          =  "&" / "|"
EXPR           =  BASE_EXPR / (LOGIC "(" EXPR ")" "(" EXPR ")")

EASY_EXPR      =  BASE_EXPR / 
                  (LOGIC "(" BASE_EXPR ")" "(" BASE_EXPR ")")

输入格式

从标准输入读入数据。

输入的第一行包含一个正整数 𝑛,表示用户的数目。

接下来 𝑛 行,每行包含空格分隔的若干个正整数,第一个正整数表示该用户的 DN,第二个正整数表示该用户具有的属性个数,此后的每两个正整数表示该用户具有的一个属性及其值。这些属性按照属性编号从小到大的顺序给出。

接下来一行包含一个正整数 𝑚,表示匹配表达式的数目。

接下来 𝑚 行,每行包含一个匹配表达式。

输出格式

输出到标准输出。

输出 𝑚 行,每行包含零个或多个正整数,用空格分隔,表示与对应的匹配表达式相匹配的用户的 DN,由小到大排序。

样例输入1

2
1 2 1 2 2 3
2 2 2 3 3 1
4
1:2
3~1
&(1:2)(2:3)
|(1:2)(3:1)

样例输出1

1

1
1 2

直接上代码和结果

#include<iostream>
#include<vector>
#include<string>
using namespace std;

class DN
{
public:
	vector<int> digit;
	int num;
};

string::iterator search(string &a)
{
	string::iterator p = a.begin() + 1;
	int count = 1;
	while (count != 0)
	{
		p++;
		if (*p == '(')
			count++;
		else if (*p == ')')
			count--;
	}
	return p;
}

bool check(string op,DN object)
{
	if (op[0]>47&&op[0]<58)
	{
		if (op[1] == ':')
		{
			if (object.digit[op[0] - '0' - 1] == op[2] - '0')
			{
				return true;
			}
			else return false;
		}
		if (op[1] == '~')
		{
			if (object.digit.size() < op[1] - '0')
			{
				return false;
			}
			else if (object.digit[op[0] - '0' - 1] != op[2] - '0')
			{
				return true;
			}
			else return false;
		}
	}
	else
	{
		string::iterator pt = search(op);
		string op1(op.begin()+2, pt);
		string op2(pt + 2, op.end() -1);
		if (op[0] == '&')
		{
			return check(op1,object) && check(op2,object);
		}
		else if (op[0] == '|')
		{
			return check(op1, object) || check(op2, object);
		}
	}
}

int main()
{
	vector<DN> list;
	vector<string> op;
	int m, n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		DN input;
		int num;
		cin >> num;
		input.num = num;
		int t;
		cin >> t;
		for (int p = 0; p < t; p++)
		{
			int a, b;
			cin >> a >> b;
			int temp;
			temp =a;
			input.digit.resize(a);
			input.digit[a - 1] = b;
		}
		list.push_back(input);
	}
	cin >> m;
	for (int x = 0; x < m; x++)
	{
		string temp;
		cin >> temp;
		op.push_back(temp);
	}
	for (int i = 0; i < op.size(); i++)
	{
		for (int t = 0; t < list.size(); t++)
		{
			if (check(op[i], list[t]))
			{
				cout << list[t].num<<" ";
			}
		}
		cout <<endl;
	}
	return 0;
}

空间占用达到了1.454个G,同时得分为0,我自己试了一下测试例是能通过的

我处理匹配表达式的思路是:将表达式的两个子表达式分开,具体的方法是找到与第一个(左括号匹配的)右括号,里面的就是第一个子表达式,往后两位的就是第二个子表达式,然后递归将这两个表达式分到不能再分,也就是原子表达式的形式,最后判断用户是否符合这个表达式来输出

求助各位大佬这个代码的问题在哪里,以及为什么会占用这么多空间,是因为递归没写对吗

是不是应该按照属性的类别来存储而不是用户的标签,这样匹配的时候可以直接用类别的地址来访问就不用顺序查找了

  • 26
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值