【CSP】2022-06-3 角色授权 大模拟 使用map优化索引+一些细节优化降低时间复杂度

文章讲述了在解决一个角色授权问题时,如何通过使用map优化索引并进行细节调整来降低时间复杂度,涉及C++编程技巧和性能优化,包括O2优化和输入处理优化。
摘要由CSDN通过智能技术生成

2022-06-3 角色授权 使用map优化索引+一些细节优化降低时间复杂度

这题目虽然看着长,但是题目的逻辑并不复杂,结构也挺清晰的,并且有也没有一些坑人的细节之类的,但是题目卡时间比较严重,而且最后竟然是用一个细节的优化方式才拿到了100分。

题目重述

这个题的数据又三个方面

一个是角色。角色有唯一的名字,有操作类型(可以多个),有可操作资源类型(可以多个),有可操作资源名字(可以多个),这些都是使用字符串类型的存储的

第二个是用户和用户组 每个用户或者用户组都可以关联多个角色。用户和用户组都有唯一的名字

第三个是待授权的操作 这个包括用户 用户组 资源类型 资源名字

思路

根据题目的数据,我们自然而然的就会想到针对每个用户/用户组存一个数组把对应的角色存下来,然后这样再判断角色是否有权限即可,这样搜索的效率就是logn(这就是建立索引的过程)

遇到的问题(学习到的东西)

这次的写代码的过程,相较之前的曲折和困难,这次还是比较顺利的,写完第一次,过了用例,就直接拿到了70分。

在这里插入图片描述

然后就想办法去优化。

  1. 尝试再新建索引优化,失败

就是在根据用户/用户组索引到角色的列表之后再用操作来索引角色,就是在map里再加一层,但是最后发现直接超时超出内存限制了。

在这里插入图片描述

  1. 尝试使用scanf输入优化输入速度

但是本来想用scanf输入,但是发现用scanf输入字符串有点困难,因为scanf是c里面的c是没有封装好的string 的所以不能直接输入,失败

  1. 使O2优化

本题的输入的数据比较多,所以考虑到优化输入,在使用scanf不行之后,突然想起来c++有自己的o2优化,就是在 前面加上三行

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    ……………………
	return 0;
}

这样就好了其他不用动

然后就可以拿到了90分在这里插入图片描述

  1. 之后又尝试了一些常数级别的优化 失败

就是使用++i而不是i++,使用set整合角色,防止重复鉴权等,都失败的了,还是90分。

  1. 参数类型问题

最后在一位博主的启发下,改变的传入函数的参数类型,就拿到了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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值