LDAP CSP CCF 202303-3 模拟 题解

题目链接: oj

解题思路

这个题的最重要思路在于递归,每个表达式都为<操作符>(表达式 1)(表达式 2)或者原子类型,但是表达式是可以嵌套的,举一个很复杂的例子:
&(&(3:1)(|(1:2)(2:3)))(|(&(2~5)(2~7))(2:5))
所以对于输入,我们先判断他是不是一个原子公式(也就是递归返回的部分),如果是原子公式就直接处理。如果是带操作符的,我们就递归获取表达式1和表达式2的结果,再根据操作符进行并集和交集运算即可。
记录一个新学到的函数lower_bound()是algorithm库的函数->找到范围内不小于目标值的第一个元素

AC代码

#include <bits/stdc++.h>
#include <stdlib.h>
using namespace std;
int m, n, ptr = 0;
string s;
vector<int> dn;
vector<vector<pair<int, int>>> attr;
// 返回一个字符串,获取一个单元(一串数字,符号,括号)
string getToken()
{
    string buf = "";
    // 是数字
    if (s[ptr] <= '9' && s[ptr] >= '0')
    {
        while (s[ptr] <= '9' && s[ptr] >= '0')
        {
            buf += s[ptr];
            ptr++;
        }
    }
    else
    {
        buf += s[ptr];
        ptr++;
    }
    return buf;
}

vector<int> calculate(vector<int> dnlist)
{
    vector<int> ans;
    string tk = getToken(); // 当前Token
    if (tk[0] == '&' || tk[0] == '|')
    {
        char c = tk[0];
        getToken(); //   (
        vector<int> res1 = calculate(dnlist);
        getToken(); //   )
        getToken(); //   (
        if (c == '&')
        { // 与操作
            ans = calculate(res1);
        }
        else
        { // 或操作
            vector<int> res2 = calculate(dnlist);
            for (int i : res2)
            {
                res1.insert(res1.end(), i);
            }
            sort(res1.begin(), res1.end());
            ans.insert(ans.end(), res1.begin(), unique(res1.begin(), res1.end())); // 取交集
        }
        getToken(); // 最后还要跳过右括号
    }
    else
    { // 原子表达式
        int key, value;
        key = atoi(tk.data());
        tk = getToken();
        char sign = tk[0];
        tk = getToken();
        value = atoi(tk.data());
        for (int i : dnlist)
        {
            auto a = lower_bound(attr[i].begin(), attr[i].end(), make_pair(key, 0));
            // fail 没找到或者找到的不是key
            if (a == attr[i].end()||(*a).first != key)
            {
                continue;
            }
            else
            {
                if ((sign == ':' && (*a).second == value) || (sign == '~' && (*a).second != value))
                {
                    ans.push_back(i);
                }
            }
        }
    }
    return ans;
}
int main()
{
    vector<int> orilist;
    scanf("%d", &n);
    dn.resize(n);
    attr.resize(n);
    for (int i = 0; i < n; i++)
    {
        int num;
        scanf("%d%d", &dn[i], &num);
        attr[i].resize(num);
        for (int j = 0; j < num; j++)
        {
            scanf("%d%d", &attr[i][j].first, &attr[i][j].second);
        }
        orilist.push_back(i);
    }
    scanf("%d", &m);
    for (int i = 0; i < m; i++)
    {
        cin >> s;
        ptr = 0;
        vector<int> ans = calculate(orilist);
        vector<int> print;
        for (int j : ans)
        {
            print.push_back(dn[j]);
        }
        sort(print.begin(), print.end());
        for (int j : print)
        {
            printf("%d ", j);
        }
        printf("\n");
    }
    return 0;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值