LDAP
好好好,难度直线上升,是一道又有了字符串处理味道的第三题
第一把写官网40分,acwing TLE且只通过了一道数据…本文是自己这题奋斗过程 的一个记录
先贴个40分的代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII; // key and value pair
int n;
unordered_map<int, unordered_map<string, string> > user; //每个用户对应一个key and value的映射表
unordered_map<string, unordered_set<int> > key_user; //i作为key, 表示哪些用户具有属性i
//处理一个基本表达式,检查基本表达式与dn的用户是否匹配
set<int> base_expr(string expr)
{
int i = 0;
while(expr[i] != ':' && expr[i] != '~') i ++;
string arr = expr.substr(0, i);
string value = expr.substr(i + 1, expr.size() - i - 1);
set<int> res;
unordered_set<int> users = key_user[arr];
if(expr[i] == ':'){
for(auto x : users){ //遍历每一个用户
if(user[x][arr] == value){
res.insert(x);
}
}
}else{
for(auto x : users){
if(user[x][arr] != value){
res.insert(x);
}
}
}
return res;
}
//处理一个常规的表达式
set<int> handle(string expr)
{
set<int> ans;
//括号要成对取出
if(expr[0] == '&' || expr[0] == '|'){
stack<char> s; int i = 2;
set<int> res1, res2;
s.push('(');
int cnt = 1;
while(!s.empty()){
while(expr[i] != '(' && expr[i] != ')') i ++;
if(expr[i] == '(') { s.push('('); cnt ++; } //入栈并进行计数
else if(expr[i] == ')') s.pop(); //弹出一个栈顶的
i ++;
}
//此时第一个括号提取完毕
string expr1 = expr.substr(2, i - 3);
string expr2 = expr.substr(i + 1, expr.size() - i - 2);
//cout << "两个表达式分别为:\n" << expr1 <<"\n" << expr2 <<"\n";
if(cnt == 1){ //此时是一个简单表达式
res1 = base_expr(expr1);
res2 = base_expr(expr2);
}
else{
res1 = handle(expr1);
res2 = handle(expr2);
}
if(expr[0] == '&'){ //取两个集合的交集
for(auto x : res1){ //遍历一个集合就可以了
if(res2.count(x)) ans.insert(x);
}
}else{ //取两个集合的并集
for(auto x : res1) ans.insert(x);
for(auto x : res2) ans.insert(x);
}
}
else { //若要处理的输入就是一个基本表达式
ans = base_expr(expr);
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
for(int i = 0;i < n;i ++){
int dn, x;
string arr, val;
cin >> dn >> x;
while(x --){
cin >> arr >> val;
key_user[arr].insert(dn); //dn具有属性arr
user[dn][arr] = val; //dn具有属性arr,且value = val
}
}
int m; cin >> m;
string line;
while(m --){
cin >> line;
set<int> ans = handle(line);
for(auto x : ans){
cout << x <<' ';
}
cout << "\n";
}
return 0;
}
秉持着自己的逻辑应该没错但是官网是40分错误的判断,我找了几分代码比对着修改了一下,找到了一个逻辑错误。
在handle
函数中我统计了一个cnt
用于控制当括号里面的是基础表达式的时候就直接调用base_expr
函数,问题就出在这里。
· 第一个问题:我只统计了第一个括号的层数,我默认这两个括号的层级是一样的。这样会导致错误,也就是当前一个括号里是基本表达式而第二个括号里面并不是的时候,此时base_expr
并不能解决这样的表达式
· 第二个问题:这里也不算会直接导致错误的原因。在handle
函数中,如果发现不是一个逻辑表达式的话,其实有调用base_expr
函数的。因此不用重复写,直接一直迭代向下调用handle
函数即可。
修改后代码运行超时,逻辑问题变优化问题了,先放个70分的代码(代码几乎没变,就是handle
函数体内部改变)
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII; // key and value pair
int n;
unordered_map<int, unordered_map<string, string> > user; //每个用户对应一个key and value的映射表
unordered_map<string, unordered_set<int> > key_user; //i作为key, 表示哪些用户具有属性i
//处理一个基本表达式,检查基本表达式与dn的用户是否匹配
set<int> base_expr(string expr)
{
int i = 0;
while(expr[i] != ':' && expr[i] != '~') i ++;
string arr = expr.substr(0, i);
string value = expr.substr(i + 1, expr.size() - i - 1);
set<int> res;
unordered_set<int> users = key_user[arr];
if(expr[i] == ':'){
for(auto x : users){ //遍历每一个用户
if(user[x][arr] == value){
res.insert(x);
}
}
}else{
for(auto x : users){
if(user[x][arr] != value){
res.insert(x);
}
}
}
return res;
}
//处理一个常规的表达式
set<int> handle(string expr)
{
set<int> ans;
//括号要成对取出
if(expr[0] == '&' || expr[0] == '|'){
stack<char> s; int i = 2;
set<int> res1, res2;
s.push('(');
while(!s.empty()){
while(expr[i] != '(' && expr[i] != ')') i ++;
if(expr[i] == '(') s.push('('); //入栈并进行计数
else if(expr[i] == ')') s.pop(); //弹出一个栈顶的
i ++;
}
//此时第一个括号提取完毕
string expr1 = expr.substr(2, i - 3);
string expr2 = expr.substr(i + 1, expr.size() - i - 2);
//cout << "两个表达式分别为:\n" << expr1 <<"\n" << expr2 <<"\n";
res1 = handle(expr1);
res2 = handle(expr2);
if(expr[0] == '&'){ //取两个集合的交集
for(auto x : res1){ //遍历一个集合就可以了
if(res2.count(x)) ans.insert(x);
}
}else{ //取两个集合的并集
for(auto x : res1) ans.insert(x);
for(auto x : res2) ans.insert(x);
}
}
else { //若要处理的输入就是一个基本表达式
ans = base_expr(expr);
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
for(int i = 0;i < n;i ++){
int dn, x;
string arr, val;
cin >> dn >> x;
while(x --){
cin >> arr >> val;
key_user[arr].insert(dn); //dn具有属性arr
user[dn][arr] = val; //dn具有属性arr,且value = val
}
}
int m; cin >> m;
string line;
while(m --){
cin >> line;
set<int> ans = handle(line);
for(auto x : ans){
cout << x <<' ';
}
cout << "\n";
}
return 0;
}
明天我来看看满分要怎么优化!!!