CSP认证:权限查询

问题描述:

201612-3权限查询
大概题意:

  • 权限:有不分等级权限与分等级权限。分等级权限给出最高权限。
  • 角色:具有多个权限
  • 用户:具有多个角色,角色之间的权限有可能重复,分等级权限取最高等级。

有q个询问:给出用户和对应权限,判断该用户是否有对应权限,若是分等级权限,则给出该用户拥有的最高等级。

大致思路:

按题目要求,根据输入处理权限、角色和用户。
我们需要根据用户查找到角色,再根据角色查找对应的权限。
询问是判断用户与权限的关系。因此,在处理用户的时候,不存储对应的角色,而是参照输入的角色名,查找对应的权限,并存储下来。使得用户与权限直接对应

大模拟题重在思考如何存储

  • 权限:结构体
struct Privilege{
	string pName;//权限类名
	mutable int maxLevel;//权限对应的最高等级,若为不分等级的权限,值为-1
	//mutable 是为了maxLevel可更新,若删去会报错
	bool operator<(const Privilege &w)const{//当多个权限需要排序时,按照pName升序排序
		return pName<w.pName;
	}
}
  • 角色集合与用户集合:unordered_map
    经过前面的分析,角色与用户都是存储名字(一个string)与权限(多个Privilege)之间对应关系。
  1. 多个Privilege:根据题意需要实现去重。可以使用set<Privilege>来存储权限集合。

set可以用二叉树搜索树实现,set有两个特点:

  1. set中的元素不允许重复
  2. set内部会维护一个严格的弱排序关系
  1. 名字(一个string)与权限(多个Privilege)之间的对应:且根据名字需要快速查找相应的权限,可以使用unordered_map<string, set<Privilege>>来存储角色集合/用户集合。

unordered_map底层采用哈希表的存储结构,特点如下:

  1. 和pair类似,用key:value的形式存储数据,key互不相同且不能修改,当关键字不是int类型时,非常方便;
  2. 与map相比,unordered_map顾名思义是无序
  3. 查找时间复杂度O(1);

OK~上代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
#include <unordered_map>

using namespace std;

struct Privilege{
    string pName;
    mutable int maxLevel;//值-1表示不分等级
    bool operator< (const Privilege &w)const{
        return pName<w.pName;
    }
};

unordered_map<string,set<Privilege>> role,user;

Privilege getPrivilege(string str){//权限的构造函数
    Privilege pr;
    int t=str.find(':');
    if(t==-1){//不分等级
        pr.pName=str;
        pr.maxLevel=-1;
    }
    else{//分等级
        pr.pName=str.substr(0,t);
        pr.maxLevel=str[t+1]-'0';
    }
    return pr;
}

int main(){
    int n;
    string str;
    string name;
    int cnt;
    /*处理权限:
        由题意得角色对应的权限列表一定是合法的,
        则用户只需要根据角色定义的权限查询即可,
        因此权限读入之后用不到,因此不需要存储
    */
    cin>>n;
    while(n--) cin>>str;
    /*处理角色*/
    cin>>n;
    while(n--){
        cin>>name>>cnt;
        while(cnt--){
            cin>>str;
            Privilege p=getPrivilege(str);
            set<Privilege> &r=role[name];//表示该角色对应权限的集合
            if(p.maxLevel==-1)//当前权限不分等级,直接添加
                r.insert(p);
            else{//当前权限分等级
                if(!r.count(p))//该角色中目前还没有该权限
                    r.insert(p);
                else{//该角色已有该权限
                    auto it=r.find(p);
                    it->maxLevel=max(it->maxLevel,p.maxLevel);
                }
            }
        }
    }
    /*处理用户*/
    cin>>n;
    while(n--){
        cin>>name>>cnt;
        set<Privilege> &u=user[name];//该用户对应权限的集合
        while(cnt--){
            cin>>str;
            set<Privilege> &ps=role[str];
            for(Privilege p:ps){//对输入角色拥有的权限逐一判断
                if(p.maxLevel==-1)//当前权限不分等级,直接添加
                    u.insert(p);
                else{//当前权限分等级
                    if(!u.count(p))//该用户中目前还没有该权限
                        u.insert(p);
                    else{//该用户已有该权限
                        auto it=u.find(p);
                        it->maxLevel=max(it->maxLevel,p.maxLevel);
                    }
                }
            }
        }
    }
    /*处理询问*/
    cin>>n;
    while(n--){
        cin>>name;
        cin>>str;
        if(!user.count(name)){//用户不存在
            cout<<"false"<<endl;
            continue;
        }
        Privilege q=getPrivilege(str);
        set<Privilege> &u=user[name];
        if(!u.count(q)){//该用户无该权限类型
            cout<<"false"<<endl;
        }
        else{
            auto it=u.find(q);
            if(it->maxLevel==-1){//该权限不分等级
                cout<<"true"<<endl;
            }
            else{
                if(q.maxLevel==-1){//询问不带等级的分等级权限
                    cout<<it->maxLevel<<endl;
                }
                else{
                    if(it->maxLevel>=q.maxLevel) cout<<"true"<<endl;
                    else cout<<"false"<<endl;
                }
            }
        }
    }
    return 0;
}

一些小Tips

  1. structsetunordered_map的使用场景和使用方法(上面已经提到啦~)
  2. find() 函数的运用:
    find()是STL容器中非常常见的操作。作用也非常好理解,就查找容器中的元素。
    在本题中使用到:
    (1) string :
    str.find(str2) 当str2是str子串时,返回在str中第一次出现的地址(下标);如果在str中找不到str2,则返回string::npos,也就是-1
    str.find(str2,pos)从str的pos号位置开始匹配,返回结果同上;
    (2) set :
    find(value) 返回set中对应值为value的迭代器,如set<int>::iterator it = st.find(2);更多时候方便简写成auto it=st.find(2);
    (3) unordered_map/map :
    与set类似,返回的也是迭代器
  3. substr() 函数的运用:
    substr(pos,len) 返回从pos号位开始,长度为len的子串;
    若len省略,则是从pos号位开始到结尾结束的子串;
    在字符串处理,尤其是一行当中有多个元素需要分隔处理的时候,非常有帮助!

参考了一些

[1]. Acwing(安利一波y总大佬🙏 讲题很清晰 也好懂~)
[2]. 《算法笔记》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值