2022-06-3 角色授权 使用map优化索引+一些细节优化降低时间复杂度
2022-06-3 角色授权 使用map优化索引+一些细节优化降低时间复杂度
这题目虽然看着长,但是题目的逻辑并不复杂,结构也挺清晰的,并且有也没有一些坑人的细节之类的,但是题目卡时间比较严重,而且最后竟然是用一个细节的优化方式才拿到了100分。
题目重述
这个题的数据又三个方面
一个是角色。角色有唯一的名字,有操作类型(可以多个),有可操作资源类型(可以多个),有可操作资源名字(可以多个),这些都是使用字符串类型的存储的
第二个是用户和用户组 每个用户或者用户组都可以关联多个角色。用户和用户组都有唯一的名字
第三个是待授权的操作 这个包括用户 用户组 资源类型 资源名字
思路
根据题目的数据,我们自然而然的就会想到针对每个用户/用户组存一个数组把对应的角色存下来,然后这样再判断角色是否有权限即可,这样搜索的效率就是logn(这就是建立索引的过程)
遇到的问题(学习到的东西)
这次的写代码的过程,相较之前的曲折和困难,这次还是比较顺利的,写完第一次,过了用例,就直接拿到了70分。
然后就想办法去优化。
- 尝试再新建索引优化,失败
就是在根据用户/用户组索引到角色的列表之后再用操作来索引角色,就是在map里再加一层,但是最后发现直接超时超出内存限制了。
- 尝试使用scanf输入优化输入速度
但是本来想用scanf输入,但是发现用scanf输入字符串有点困难,因为scanf是c里面的c是没有封装好的string 的所以不能直接输入,失败
- 使O2优化
本题的输入的数据比较多,所以考虑到优化输入,在使用scanf不行之后,突然想起来c++有自己的o2优化,就是在 前面加上三行
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
……………………
return 0;
}
这样就好了其他不用动
然后就可以拿到了90分
- 之后又尝试了一些常数级别的优化 失败
就是使用++i而不是i++,使用set整合角色,防止重复鉴权等,都失败的了,还是90分。
- 参数类型问题
最后在一位博主的启发下,改变的传入函数的参数类型,就拿到了100
就是函数在进行只读操作时,使用引用传递(const “type” &)比起直接传入参数效率更高。
bool check_all(struct behave t,unordered_set<int> s) { …… } bool check_roler(struct behave t, int id) { …… }
改为
bool check_roler(const struct behave &t, const int &id) { …… } bool check_all(const struct behave &t,const unordered_set<int> &s) { ………… }
然后就直接时间大大缩短,拿到了100分
最后也是没想到,csp考试竟然要卡你这种样的点,不让你过,不过还是学一学这些优化,防止他再去考。
完整代码
#include <bits/stdc++.h>
using namespace std;
int n, m, q;
struct roler
{
string name;
unordered_map<string, int> op;
bool op_all;
unordered_map<string, int> src_kind;
bool src_kind_all;
unordered_map<string, int> src_name;
bool src_name_all;
} r[501];
unordered_map<string, int> name_to_roler;
struct roler_user
{
string name;
vector<string> user;
vector<string> group;
} con[501];
struct behave
{
string user_name;
vector<string> group;
string operat;
string src_kind;
string src_name;
} un[5001];
unordered_map<string, unordered_set<int>> user_to_roler;
unordered_map<string, unordered_set<int>> group_to_roler;
// 检查这个角色有没有权限
bool check_roler(const struct behave &t, const int &id)
{
// 检查该角色的操作清单,如果该角色的操作清单中不包含该操作,
// 且该角色的操作清单中也不包含字符串 *,那么不能执行该操作;
if (!r[id].op_all && r[id].op[t.operat] != 1)
return false;
// 检查该角色的资源种类清单,如果该角色的资源种类清单中不包含该资源的种类,
// 且该角色的资源种类清单中也不包含字符串 *,那么不能执行该操作;
if (!r[id].src_kind_all && r[id].src_kind[t.src_kind] != 1)
return false;
// 检查该角色的资源名称清单,如果该角色的资源名称清单中不包含该资源的名称,
// 且该角色的资源名称清单不是空数组,那么不能执行该操作;
if (!r[id].src_name.empty() && r[id].src_name[t.src_name] != 1)
return false;
return true;
}
bool check_all(const struct behave &t,const unordered_set<int> &s)
{
for (auto item : s)
{
if (check_roler(t, item))
{
return true;
}
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// freopen("1.txt", "r", stdin);
cin >> n >> m >> q;
// 输入n个角色
for (int i = 0; i < n; ++i)
{
string name;
cin >> r[i].name;
name_to_roler[r[i].name] = i;
int nv;
cin >> nv;
for (int j = 0; j < nv; ++j)
{
string ops;
cin >> ops;
if (ops == "*")
r[i].op_all = true;
r[i].op[ops] = 1;
}
int no;
cin >> no;
for (int j = 0; j < no; ++j)
{
string type; // 资源种类
cin >> type;
if (type == "*")
r[i].src_kind_all = true;
r[i].src_kind[type] = 1;
}
int nn;
cin >> nn;
for (int j = 0; j < nn; ++j)
{
string name; // 资源名字
cin >> name;
r[i].src_name[name] = 1;
}
}
// 输入m个角色关联
for (int i = 0; i < m; ++i)
{
int ns;
cin >> con[i].name >> ns;
for (int j = 0; j < ns; ++j)
{
string type, name;
cin >> type >> name;
if (type == "u")
{
con[i].user.push_back(name);
if (name_to_roler.count(con[i].name)) // 如果有这个角色才加入
user_to_roler[name].insert(name_to_roler[con[i].name]);
}
if (type == "g")
{
con[i].group.push_back(name);
if (name_to_roler.count(con[i].name)) // 如果有这个角色才加入
group_to_roler[name].insert(name_to_roler[con[i].name]);
}
}
}
// 输入q个待授权的操作
for (int i = 0; i < q; ++i)
{
string name;
int ng;
cin >> name >> ng;
un[i].user_name = name;
for (int j = 0; j < ng; ++j)
{
string groupname;
cin >> groupname;
un[i].group.push_back(groupname);
}
string opera;
string srckind, srcname;
cin >> opera;
cin >> srckind >> srcname;
un[i].operat = opera;
un[i].src_kind = srckind;
un[i].src_name = srcname;
}
for (int i = 0; i < q; ++i)
{
bool flag = false;
unordered_set<int> all_roler; // 防止重复判断
unordered_set<int> temp1 = user_to_roler[un[i].user_name];
all_roler.insert(temp1.begin(), temp1.end());
for (int j = 0; j < un[i].group.size(); ++j)
{
unordered_set<int> temp = group_to_roler[un[i].group[j]];
all_roler.insert(temp.begin(), temp.end());
}
if (check_all(un[i], all_roler))
{
flag = true;
}
if (flag)
cout << 1 << endl;
else
cout << 0 << endl;
}
return 0;
}
第二遍写精简版
#include <bits/stdc++.h>
using namespace std;
int n, m, q;
struct roler
{
string name;
bool d_all;
bool kind_all;
bool src_all;
vector<string> d;
vector<string> kind;
vector<string> src;
} r[501];
unordered_map<string, int> n_to_r;
unordered_map<string, set<int>> u_to_r;
//map<string, map<string, set<int>>> u_to
bool check_roler(const struct roler &role,const string &d, const string &kind, const string &src)
{
if(!role.d_all)
{
bool flag = false;
for(int i = 0; i < role.d.size(); i++)
{
if(role.d[i] == d)
{
flag = true;
break;
}
}
if(!flag) return false;
}
if(!role.kind_all)
{
bool flag = false;
for(int i = 0; i < role.kind.size(); i++)
{
if(role.kind[i] == kind)
{
flag = true;
break;
}
}
if(!flag) return false;
}
bool flag =false;
if(!role.src.size()) flag = true;
for(int i = 0; i < role.src.size(); i++)
{
if(role.src[i] == src)
{
flag = true;
break;
}
}
if(!flag) return false;
return true;
}
bool check_user(const set<int> &roles, const string &d, const string &kind, const string &src)
{
for(auto item : roles)
{
if(check_roler(r[item], d, kind, src))
{
return true;
}
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> q;
for(int i = 0; i < n; i++)
{
cin >> r[i].name;
n_to_r[r[i].name] = i;
int nv;
cin >> nv;
for(int j = 0; j < nv; j++)
{
string temp;
cin >> temp;
if(temp == "*")
r[i].d_all = true;
r[i].d.push_back(temp);
}
int no;
cin >> no;
for(int j = 0; j < no; j++)
{
string temp;
cin >> temp;
if(temp == "*")
r[i].kind_all = true;
r[i].kind.push_back(temp);
}
int nn;
cin >> nn;
for(int j = 0; j < nn; j++)
{
string temp;
cin >> temp;
r[i].src.push_back(temp);
}
}
for(int i = 0; i < m; i++)
{
string rn;
int ns,index;
cin >> rn;
cin >> ns;
index = n_to_r[rn];
for(int j = 0; j < ns; j++)
{
string type, name;
cin >> type >> name;
u_to_r[name].insert(index);
}
}
for(int i = 0; i < q; i++)
{
set<int> r_all;
string uname;
int ng;
cin >> uname;
r_all.insert(u_to_r[uname].begin(),u_to_r[uname].end());
cin >> ng;
for(int j = 0; j < ng; j++)
{
string temp;
cin >> temp;
r_all.insert(u_to_r[temp].begin(),u_to_r[temp].end());
}
string d, kind, src;
cin >> d >> kind >>src;
if(check_user(r_all, d, kind, src)) cout << 1 <<endl;
else cout << 0 <<endl;
}
return 0;
}