1. 程式人生 > >CCF201612-3 許可權查詢(100分)

CCF201612-3 許可權查詢(100分)

試題編號: 201612-3
試題名稱: 許可權查詢
時間限制: 1.0s
記憶體限制: 256.0MB
問題描述: 問題描述   授權 (authorization) 是各類業務系統不可缺少的組成部分,系統使用者通過授權機制獲得系統中各個模組的操作許可權。
  本題中的授權機制是這樣設計的:每位使用者具有若干角色,每種角色具有若干許可權。例如,使用者 david 具有 manager 角色,manager 角色有 crm:2 許可權,則使用者 david 具有 crm:2 許可權,也就是 crm 類許可權的第 2 等級的許可權。
  具體地,使用者名稱和角色名稱都是由小寫字母組成的字串,長度不超過 32。許可權分為分等級許可權和不分等級許可權兩大類。分等級許可權由許可權類名和許可權等級構成,中間用冒號“:”分隔。其中許可權類名也是由小寫字母組成的字串,長度不超過 32。許可權等級是一位數字,從 0 到 9,數字越大表示許可權等級越高。系統規定如果使用者具有某類某一等級的許可權,那麼他也將自動具有該類更低等級的許可權。例如在上面的例子中,除 crm:2 外,使用者 david 也具有 crm:1 和 crm:0 許可權。不分等級許可權在描述許可權時只有許可權類名,沒有許可權等級(也沒有用於分隔的冒號)。
  給出系統中使用者、角色和許可權的描述資訊,你的程式需要回答多個關於使用者和許可權的查詢。查詢可分為以下幾類:
  * 不分等級許可權的查詢:如果許可權本身是不分等級的,則查詢時不指定等級,返回是否具有該許可權;
  * 分等級許可權的帶等級查詢:如果許可權本身分等級,查詢也帶等級,則返回是否具有該類的該等級許可權;
  * 分等級許可權的不帶等級查詢:如果許可權本身分等級,查詢不帶等級,則返回具有該類許可權的等級;如果不具有該類的任何等級許可權,則返回“否”。 輸入格式   輸入第一行是一個正整數 p,表示不同的許可權類別的數量。緊接著的 p 行被稱為 P 段,每行一個字串,描述各個許可權。對於分等級許可權,格式為 <category>:<level>,其中 <category> 是許可權類名,<level> 是該類許可權的最高等級。對於不分等級許可權,字串只包含許可權類名。
  接下來一行是一個正整數 r,表示不同的角色數量。緊接著的 r 行被稱為 R 段,每行描述一種角色,格式為
  <role> <s> <privilege 1> <privilege 2> ... <privilege s>
  其中 <role> 是角色名稱,<s> 表示該角色具有多少種許可權。後面 <s> 個字串描述該角色具有的許可權,格式同 P 段。
  接下來一行是一個正整數 u,表示使用者數量。緊接著的 u 行被稱為 U 段,每行描述一個使用者,格式為
  <user> <t> <role 1> <role 2> ... <role t>
  其中 <user> 是使用者名稱,<t> 表示該使用者具有多少種角色。後面 <t> 個字串描述該使用者具有的角色。
  接下來一行是一個正整數 q,表示許可權查詢的數量。緊接著的 q 行被稱為 Q 段,每行描述一個授權查詢,格式為 <user> <privilege>,表示查詢使用者 <user> 是否具有 <privilege> 許可權。如果查詢的許可權是分等級許可權,則查詢中的 <privilege> 可指定等級,表示查詢該使用者是否具有該等級的許可權;也可以不指定等級,表示查詢該使用者具有該許可權的等級。對於不分等級許可權,只能查詢該使用者是否具有該許可權,查詢中不能指定等級。 輸出格式   輸出共 q 行,每行為 false、true,或者一個數字。false 表示相應的使用者不具有相應的許可權,true 表示相應的使用者具有相應的許可權。對於分等級許可權的不帶等級查詢,如果具有許可權,則結果是一個數字,表示該使用者具有該許可權的(最高)等級。如果使用者不存在,或者查詢的許可權沒有定義,則應該返回 false。 樣例輸入 3
crm:2
git:3
game
4
hr 1 crm:2
it 3 crm:1 git:1 game
dev 2 git:3 game
qa 1 git:2
3
alice 1 hr
bob 2 it qa
charlie 1 dev
9
alice game
alice crm:2
alice git:0
bob git
bob poweroff
charlie game
charlie crm
charlie git:3
malice game 樣例輸出 false
true
false
2
false
true
false
true
false 樣例說明   樣例輸入描述的場景中,各個使用者實際的許可權如下:
  * 使用者 alice 具有 crm:2 許可權
  * 使用者 bob 具有 crm:1、git:2 和 game 許可權
  * 使用者 charlie 具有 git:3 和 game 許可權
  * 使用者 malice 未描述,因此不具有任何許可權 評測用例規模與約定   評測用例規模:
  * 1 ≤ p, r, u ≤ 100
  * 1 ≤ q ≤ 10 000
  * 每個使用者具有的角色數不超過 10,每種角色具有的許可權種類不超過 10
  約定:
  * 輸入保證合法性,包括:
  1) 角色對應的許可權列表(R 段)中的許可權都是之前(P 段)出現過的,許可權可以重複出現,如果帶等級的許可權重複出現,以等級最高的為準
  2) 使用者對應的角色列表(U 段)中的角色都是之前(R 段)出現過的,如果多個角色都具有某一分等級許可權,以等級最高的為準
  3) 查詢(Q 段)中的使用者名稱和許可權類名不保證在之前(U 段和 P 段)出現過
  * 前 20% 的評測用例只有一種角色
  * 前 50% 的評測用例許可權都是不分等級的,查詢也都不帶等級

問題描述(參見上文)。

問題分析:這個問題是RBAC問題,即基於角色的許可權訪問問題,是商業應用中必然出現的問題。商業應用中,通常將這些資料儲存於資料庫中。這個問題只要採用合適的資料結果來儲存有關資料即可,查詢處理過程相對比較簡單。

程式說明:程式中,使用了三個結構向量分別用來儲存許可權、角色和使用者。查詢用的資料則不需要儲存。查詢過程根據題意進行處理即可。測試樣例中,似乎沒有使用許可權資料,對許可權資料不做任何處理也可以的100分,有點怪怪的。

提交後得100分的C++語言程式如下:

/* CCF201612-3 許可權查詢 */

#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>

const int NOVALUE = -1;
const int TRUE = -2;
const int FALSE = -3;

using namespace std;

// 許可權
struct _privilege {
    string category;
    int level;
};
vector<_privilege> privilege;

// 角色
struct _role {
    string role;
    int s;
    vector<_privilege> privilege;
};
vector<_role> role;

// 使用者
struct _user {
    string user;
    int t;
    vector<string> role;
};
vector<_user> user;

string getcategory(string& s)
{
    int pos = s.find(":");

    if(pos == (int)string::npos)
        return s;
    else
        return s.substr(0, pos);
}

int getlevel(string &s)
{
    int pos = s.find(":");

    if(pos == (int)string::npos)
        return NOVALUE;
    else
        return atoi(s.substr(pos+1, s.length()-1).c_str());
}

int privilegematch(_privilege& p1, _privilege& p2)
{
    if(p1.category != p2.category)
        return FALSE;
    else if(p2.level == NOVALUE) {
        // 不分等級查詢
        if(p1.level == NOVALUE)
            return TRUE;
        else
            return p1.level;
    } else {    // p2.level >= 0
        // 分等級查詢
        if(p1.level == NOVALUE)
            return TRUE;
        else {
            if(p1.level >= p2.level)
                return TRUE;
            else
                return FALSE;
        }
    }
}

int rolematch(string& rl, _privilege& prvl)
{
    int ans = FALSE;

    for(int i=0; i<(int)role.size(); i++) {
        if(role[i].role == rl) {
            for(int j=0; j<role[i].s; j++) {
                int rt = privilegematch(role[i].privilege[j], prvl);
                if(rt > ans)
                    ans = rt;
            }
        }
    }

    return ans;
}

int query(string& usr, _privilege& prvl)
{
    for(int i=0; i<(int)user.size(); i++) {
        if(user[i].user == usr) {
            int ans = FALSE;
            for(int j=0; j<user[i].t; j++) {
                int rt = rolematch(user[i].role[j], prvl);
                if(rt > ans)
                    ans = rt;
            }
            return ans;
        }
    }

    return FALSE;
}

int main()
{
    int p, r, u, q;

    // 輸入許可權類別數量
    cin >> p;
    // 輸入許可權類別
    string c;
    _privilege prvl;
    for(int i=1; i<=p; i++) {
        cin >> c;

        prvl.category = getcategory(c);
        prvl.level = getlevel(c);
        privilege.push_back(prvl);
    }

    // 輸入角色數量r
    cin >> r;
    // 輸入角色
    for(int i=1; i<=r; i++) {
        _role rl;

        cin >> rl.role >> rl.s;

        for(int j=1; j<=rl.s; j++) {
            cin >> c;

            prvl.category = getcategory(c);
            prvl.level = getlevel(c);
            rl.privilege.push_back(prvl);
        }
        role.push_back(rl);
    }

    // 輸入使用者數量u
    cin >> u;
    // 輸入使用者
    for(int i=1; i<=u; i++) {
        _user us;

        cin >> us.user >> us.t;

        for(int j=1; j<=us.t; j++) {
            cin >> c;

            us.role.push_back(c);
        }
        user.push_back(us);
    }

    // 輸入查詢數量q
    cin >> q;
    string suser;
    for(int i=1; i<=q; i++) {
        // 查詢輸入
        cin >> suser >> c;

        // 許可權分解
        prvl.category = getcategory(c);
        prvl.level = getlevel(c);

        // 查詢處理
        int ans = query(suser, prvl);

        // 輸出結果
        if(ans == TRUE)
            cout << "true" << endl;
        else if(ans == FALSE)
            cout << "false" << endl;
        else
            cout << ans << endl;
    }

    return 0;
}

/* 這個問題是RBAC問題,即基於角色的許可權訪問問題,是商業應用中必然出現的問題 */



相關推薦

CCF201612-3 許可權查詢100

試題編號: 201612-3 試題名稱: 許可權查詢 時間限制: 1.0s 記憶體限制: 256.0MB 問題描述: 問題描述   授權 (authorization) 是各類業務系統不可缺少的組成部分,系統使用者通過授權機制獲得系統中各個模組的操作許可

ccf201612-3許可權查詢90

        相當複雜的模擬題,有一個點不懂,就是輸入的p段不知道有什麼用,既然後面輸入的角色段裡的許可權都會包含在p段裡,那這個p段感覺沒什麼用,所以我只是做了接收字串,沒有做任何處理,可能扣的10分就來自這裡吧。     &nbs

PTA|01-複雜度3 二分查詢 20 二分查詢

本題要求實現二分查詢演算法。 函式介面定義: Position BinarySearch( List L, ElementType X ); 其中List結構定義如下: typedef int Position; typedef struct LNode *L

01-複雜度3 二分查詢 20

本題要求實現二分查詢演算法。 函式介面定義: Position BinarySearch( List L, ElementType X ); 其中List結構定義如下: typedef int

01-複雜度3 二分查詢20

本題要求實現二分查詢演算法。 函式介面定義: Position BinarySearch( List L, ElementType X ); 其中List結構定義如下: typedef int Position; typedef struct LNod

ccf 201803-3 URL對映100

問題描述   URL 對映是諸如 Django、Ruby on Rails 等網頁框架 (web frameworks) 的一個重要元件。對於從瀏覽器發來的 HTTP 請求,URL 對映模組會解析請求中的 URL 地址,並將其分派給相應的處理程式碼。現在,請你

CCF201412-3 集合競價100

試題編號: 201412-3 試題名稱: 集合競價 時間限制: 1.0s 記憶體限制: 256.0MB 問題描述: 問題描述   某股票交易所請你編寫一個程式,根據開盤前客戶提交的訂單來確定某特定股票的開盤價和開盤成交量。   該程式的輸入由很多行

CCF201612-4 壓縮編碼100

試題編號:    201612-4 試題名稱:    壓縮編碼 時間限制:    3.0s 記憶體限制:    256.0MB 問題描述:     問題描述   給定一段文字,已知單詞a1, a2, …, an出現的頻率分別t1, t2, …, tn。可以用01串給這些單詞編碼,即將每個單詞與一個01串對應,

PTA 01-複雜度3 二分查詢 20

01-複雜度3 二分查詢 (20 分) 本題要求實現二分查詢演算法。 函式介面定義: Position BinarySearch( List L, ElementType X ); 其中List結構定義如下: typedef int Position; typedef

201803-3 URL對映100

題目描述: 問題描述   URL 對映是諸如 Django、Ruby on Rails 等網頁框架 (web frameworks) 的一個重要元件。對於從瀏覽器發來的 HTTP 請求,URL 對映模組會解析請求中的 URL 地址,並將其分派給相應的處理程式

CCF 2017-3 03-Markdown java100

使用正則表示式解題,塊標籤用string.matches直接匹配,行內標籤使用Pattern達到多次出現,多次替換的效果。 程式碼得分滿分,耗時156ms import java.util.ArrayList; import java.util.List; import java.util.

CCF 201709 第三題JSON查詢 java100

自從會了正則表示式後,什麼都要用,這個題用正則反倒麻煩了。使用正則時,我卡在了多層物件的正則式上,因為百分之80的測試資料只有兩層結構,我就只得了八十分。 其實只要遍歷json的每一個字元,使用hashmap來儲存鍵和值,再加上棧來判斷當前的鍵值時屬於哪個物件就可以了。 一下程式碼得分100

CCF201403-3 命令列選項100

問題描述   請你寫一個命令列分析程式,用以分析給定的命令列裡包含哪些選項。每個命令列由若干個字串組成,它們之間恰好由一個空格分隔。這些字串中的第一個為該命令列工具的名字,由小寫字母組成,你的程式不用對它進行處理。在工具名字之後可能會包含若干選項,然後可能會包含一 些不是選項的引數。   選項有兩類:帶引數

7-13 航空公司VIP客戶查詢 25

nbsp 一點 att containe lte 沖突 分享圖片 space 移動 題意: ? 思路: 讀完題目之後的第一思路就是用map將客戶的id(string類型)與裏程road(int類型)形成映射,然後直接用id查找添加裏程或輸出裏程。但是400ms的限制妥妥的

7-3 詞頻統計30 巧解

2018年8月15日 于山東 7-3 詞頻統計(30 分) 請編寫程式,對一段英文文字,統計其中所有不同單詞的個數,以及詞頻最大的前10%的單詞。 所謂“單詞”,是指由不超過80個單詞字元組成的連續字串,但長度超過15的單詞將只擷取保留前15個單詞字元。而合法的“

7-3 括號匹配 25

給定一串字元,不超過100個字元,可能包括括號、數字、字母、標點符號、空格,程式設計檢查這一串字元中的( ) ,[ ],{ }是否匹配。 輸入格式: 輸入在一行中給出一行字串,不超過100個字元,可能包括括號、數字、字母、標點符號、空格。 輸出格式: 如果括號配對,輸出yes,否

7-3 單詞長度 15

你的程式要讀入一行文字,其中以空格分隔為若干個單詞,以.結束。你要輸出每個單詞的長度。這裡的單詞與語言無關,可以包括各種符號,比如it’s算一個單詞,長度為4。注意,行中可能出現連續的空格;最後的.不計算在內。 輸入格式: 輸入在一行中給出一行文字,以.結束 提示:用scanf(

CSP201403-1 相反數100

試題編號: 201403-1 試題名稱: 相反數 時間限制: 1.0s 記憶體限制: 256.0MB 問題描述: 問題描述         有 N 個非零且各不相同的整數。請你編一個程式求出它們中有多少對相反數(a 和 -a 為一

ccf 201604-2俄羅斯方塊 java100

最重要的是找到要下落的行數,移動的列數是起始位置-1 下落的列數是計算下落方塊陣列中為1的位置可以下落的距離,整體下降距離是這些距離中最小的。 import java.util.Scanner; public class Main{ public static void main

ccf 201412-03集合競價 java100

題目看起來並不難,按照題目的要求,一步一步編就可以。第一次提交只有80分,把成交量改為long之後得了100分。囧 import java.util.ArrayList; import java.util.List; import java.util.Scanner; class Bill{