CCF-CSP -201612-3 許可權查詢參考答案
阿新 • • 發佈:2019-01-04
試題名稱: 許可權查詢
一不小心半年多過去了。這半年。。。唉,不提了。反正以後不出意外還是要更新部落格的吧,希望不出。
經過半年的學習,回過頭來看當時寫的程式碼,真是渣啊。評論大哥說的很對,這次更新聽取意見了。先放上程式碼。思路啥的都在註釋裡寫了。由於系統崩了,沒法通過系統測試,不過樣例是對的。總共用了4個小時敲並調試出來。好吧,還要多練啊。
先上最新程式碼的執行效果:100分!
/**
* 使用者許可權查詢問題
* 之前採用的思路是,分別建立許可權/角色/使用者三個類,使用者中儲存角色,角色中儲存許可權;查詢使用者許可權時,遍歷該使用者的所有角色的所有許可權,檢視其中是否有該許可權。。。
* mmp,寫下我當時的這段思路後,我老臉都紅了。。。當時真的是一腔熱血的懟啊,一點演算法不懂,楞搞啊!當時因該是總是報執行超時,這麼搞不超時才怪啊。
* 新的思路,絕對不是最好,但是至少比傻白甜1.0時期強點吧。
*依然分為三個類:使用者/角色/許可權;但是,儲存的時候,角色只是過渡,使用者直接儲存其許可權;查詢的時候,針對某個使用者,直接查詢是否有該許可權以及許可權是否夠的問題。總的來說,應該是增加儲存時候的處理時間,但是大大減少查詢的時間。
**/
import java.util.*;
public class Main {
public static Boolean debug = false;
public static int level = 0;// 0 for info 1 for debug
public static void main(String args[]) {
//獲取資料
Scanner cin = new Scanner(System.in);
// input Privission list
int p = cin.nextInt();
Privilege[] arrayPrivi = new Privilege[p];
//List<Privi> priviList = new ArrayList<Privi>();
for (int i = 0; i < p; i++) {
arrayPrivi[i] = new Privilege(cin.next());
}
// input role list
int r = cin.nextInt();
Role[] arrayRole = new Role[r];
for (int i = 0; i < r; i++) {
String nameRole = cin.next();
int countPrivi = cin.nextInt();
Role role = new Role(nameRole, countPrivi);
for (int j = 0; j < countPrivi; j++) {
role.addPrivi(new Privilege(cin.next()));
}
arrayRole[i] = role;
}
//新增完角色後,檢視一下角色列表
if(Main.debug && Main.level > 1){
for(int j = 0; j < r; j++) {
System.out.print("新增完角色後");
System.out.println(arrayRole[j]);
}
}
// input user list;
int u = cin.nextInt();
User[] arrayUser = new User[u];
for (int i = 0; i < u; i++) {
String name = cin.next();
int countRole = cin.nextInt();
User user = new User(name);
for (int j = 0; j < countRole; j++) {
Role role = roleFactory(arrayRole,cin.next());
if(Main.debug && Main.level > 0){
System.out.println("Main:role to added:" + role);
}
user.addRole(role);
//列印使用者資訊
if(Main.debug && Main.level > 0){
System.out.println("Main: user: " + user);
}
}
arrayUser[i] = user;
//新增完使用者後,檢視一下角色列表
if(Main.debug && Main.level > 0){
for(int k = 0; k < r; k++) {
System.out.print("新增完一個使用者後role list: ");
System.out.println(arrayRole[k]);
}
}
//列印使用者資訊
if(Main.debug && Main.level > 0){
System.out.println("Main: 角色載入完後的user: " + user);
}
}
//
int q = cin.nextInt();
QueryHolder[] arrayQuery = new QueryHolder[q];
for (int i = 0; i < q; i++) {
arrayQuery[i] = new QueryHolder(cin.next(),cin.next());
}
cin.close();
if(Main.debug && Main.level > 1)
System.out.println("Main:輸入結束");
//查詢開始!
for(QueryHolder query : arrayQuery) {
User qUser = userFactory(arrayUser, query.qUserName);
if(qUser == null){
System.out.println(false);
continue;
}
if(Main.debug && Main.level > 1)
System.out.println("Main:qUser: " + qUser);
int result = qUser.quaryPrivi(query.qPrivi);
if(result == -2 )
System.out.println("false");
else if (result == -1)
System.out.println("true");
else
System.out.println("" + result);
}
}
/**根據角色名字返回角色物件
*/
private static Role roleFactory(Role[] arrayRole,String name) {
for(Role role : arrayRole) {
if(name.equals(role.getRoleName())) {
return role;
}
}
return null;
}
/**根據使用者名稱字返回使用者物件
*/
private static User userFactory(User[] arrayUser,String name) {
for(User user : arrayUser) {
if(name.equals(user.getUserName())) {
return user;
}
}
return null;
}
}
/**查詢引數持有類
*
*/
class QueryHolder {
public String qUserName;
public Privilege qPrivi;
QueryHolder(String username, String Priviname) {
this.qUserName = username;
this.qPrivi = new Privilege(Priviname);
}
public String toString() {
return "query: " + this.qUserName + " " + this.qPrivi;
}
}
/**使用者類
*
**/
class User {
//使用者名稱
private String userName;
//使用者擁有角色的數量
private int numRoles;
//使用者擁有許可權的列表
private List<Privilege> userPrivi;
/**
*建構函式
**/
public User(){}
public User(String userName){
this.userName = userName;
//this.numRoles = numRoles;
this.userPrivi = new ArrayList<Privilege>();
}
/**重寫toString()方法
*
**/
public String toString() {
String str = "user:" + this.userName + "-";
for (Privilege privi : this.userPrivi)
str += privi + " ";
return str;
}
public String getUserName() {
return this.userName;
}
/**查詢使用者是否具有某許可權
* 注意:許可權等級是0-9,所以
*@return -2(不具備該許可權/具備該許可權但是等級不夠);
*@return -1 (具備該許可權且其具有的等級不低於給出的等級);
*@return >=0的值 具備該許可權,且最高許可權為返回值;
**/
public int quaryPrivi(Privilege privi) {
for(Privilege p : this.userPrivi) {
if(p.namePrivi.equals(privi.namePrivi)){//首先檢視是否有重名許可權:
if(privi.rankPrivi <= p.rankPrivi){
//無等級許可權;直接返回0;
// 有等級許可權, 給出了許可權等級且其具有的等級不低於給出的等級, 返回 0;
if(p.rankPrivi == -1 || privi.rankPrivi != -1)
return -1;
// 有等級許可權, 但是沒給出許可權等級, 返回其擁有的最高等級許可權;
else
return p.rankPrivi;
}else
return -2;
}
}
//沒有重名許可權
return -2;
}
/**
* 獲取使用者的許可權集合
*/
public List<Privilege> getUserPrivi(){
return this.userPrivi;
}
/***新增使用者的角色屬性,
*直接將角色的許可權存到使用者的許可權列表中
*注意,新增的角色的時候,可能會出現,不同角色具有相同的許可權,但是許可權等級不同的情況;
*對於不同的角色中,許可權名相同的部分,如果都是無等級許可權或者等級相同,由於是List,自動刪除重複的。如果是不同等級的同名許可權,則保留高等級的許可權。
**/
public void addRole(Role r) {
if(Main.debug && Main.level > 0){
System.out.println("add role: user:" + this.userName);
System.out.println("add role: role to added: " + r);
}
//獲取待新增角色的許可權列表
List<Privilege> rolePrivi = r.getRolePrivi();
//獲取該使用者的許可權數量,如果數量為0,則不會存在許可權衝突的問題,直接新增所有許可權
int numUserPrivi = this.userPrivi.size();
if(numUserPrivi == 0){
this.userPrivi.addAll(rolePrivi);
return;
}
//如果該使用者已經有了部分許可權,則要判斷待新增的角色的許可權是否和已有的重複;
//獲取待新增角色的許可權的數量
int numRolePrivi = rolePrivi.size();
for(int i = 0; i < numRolePrivi; i++) {
Boolean hasSameName = false;//是否有重名許可權的標誌,每次迭代要初始化
if(Main.debug && Main.level > 1){
System.out.println("add role:" + i);
System.out.println("add role: rolePrivi:i:" + rolePrivi.size());
}
Privilege iPrivi = rolePrivi.get(i);
for (int j = 0; j < numUserPrivi; j++) {
if(Main.debug && Main.level > 1){
System.out.println("add role: userPrivi:j:" + j);
System.out.println("add role: userPrivi:j:" + this.userPrivi.size());
}
Privilege jPrivi = this.userPrivi.get(j);
if (iPrivi.namePrivi.equals(jPrivi.namePrivi)){//有重名許可權
hasSameName = true;
if(iPrivi.rankPrivi > jPrivi.rankPrivi){ //有重名許可權,且新的許可權的等級高於原許可權等級,把已有的許可權刪掉,新增新的許可權,更新使用者許可權數量
this.userPrivi.remove(j);
this.userPrivi.add(iPrivi);
//numUserPrivi = this.userPrivi.size();
}else{ //有重名許可權,且新的許可權的等級不高於原許可權等級,則不需要新增,把該許可權從角色許可權列表刪除,更新角色列表許可權的數量;
//rolePrivi.remove(i);
//numRolePrivi = rolePrivi.size();
}
//如果發現了重名許可權,因為角色許可權列表肯定沒有重名許可權,且使用者許可權列表也沒有重名許可權,因此可以跳出使用者的迴圈。
break;
}
}
//user已有的許可權和要新增的許可權都不重名:新增
if(!hasSameName){
this.userPrivi.add(iPrivi);
}
}
//排除了所有重名可能,直接新增所有許可權
//this.userPrivi.addAll(rolePrivi);
}
}
/**角色類
*
**/
class Role {
//角色名稱
private String roleName;
//角色擁有的許可權列表: 二維陣列存放格式: [[許可權1名,許可權1等級],[許可權2名,許可權2等級], ...](其中,許可權名由對應的數字表示!)
private List<Privilege> rolePrivilege;
//許可權存放數量的計數器
//private int counterPrivilege;
//public Role(){}
/**
*Role 建構函式
*@param roleName
*@param numPrivilege 該角色擁有的許可權種類數目,由此初始化rolePrivilege
**/
public Role(String roleName, int numOfPrivilege){
this.roleName = roleName;
//this.counterPrivilege = 0;
this.rolePrivilege = new ArrayList<Privilege>();
}
public String toString() {
String str = "Role:" + this.roleName + "-";
for (Privilege privi : rolePrivilege)
str += privi + " ";
return str;
}
public String getRoleName(){
return this.roleName;
}
public List<Privilege> getRolePrivi(){
return this.rolePrivilege;
}
/**為角色增加許可權;
* 注意!許可權可以重複出現,如果帶等級的許可權重複出現,以等級最高的為準
*@param Privilege 許可權字串,格式:name:rank; 如 crm:1
*為降低空間,提高速度,直接將name根據對映關係記錄成數字;
**/
public void addPrivi(Privilege privi) {
//獲取許可權的名字
String namePrivi = privi.namePrivi;
//獲取許可權的等級
int rankPrivi = privi.rankPrivi;
//獲取該角色已有的許可權的數量
int numRolePrivi = this.rolePrivilege.size();
//確認是否有重複的許可權,重複的許可權儲存最高的許可權。
Boolean hasSameName = false;
Privilege iPrivi = null;
for (int i =0; i < numRolePrivi; i++) { //遍歷已有的許可權列表
iPrivi = this.rolePrivilege.get(i);
if (iPrivi.namePrivi.equals(namePrivi)){ //有重名許可權
hasSameName = true;
if(iPrivi.rankPrivi < rankPrivi){//替換列表中等級較低的許可權
this.rolePrivilege.remove(i);
this.rolePrivilege.add(privi);
}
//如果iprivi.rankprivi >= rankprivi:
//不移除、不新增,後面也不操作
break;
}
}
if(!hasSameName)
this.rolePrivilege.add(privi);
}
}
/**許可權類
*為了提高速度,將Privilege直接儲存為陣列;[p1,p2,p3....]
*/
class Privilege {
public String namePrivi;
//許可權等級是0-9,所以-1表示為無等級許可權;
public int rankPrivi;
public Privilege(){}
/**
*
*/
public Privilege(String nk){
String[] privi = nk.split(":");
if(privi.length == 2){
this.namePrivi = privi[0];
this.rankPrivi = Integer.parseInt(privi[1]);
}else if (privi.length == 1) {
this.namePrivi = privi[0];
this.rankPrivi = -1;
}else {
this.namePrivi = "utility";
this.rankPrivi = -1;
}
}
public Privilege(String namePrivi, int rankPrivi){
this.namePrivi = namePrivi;
this.rankPrivi = rankPrivi;
}
public String toString() {
if(this.rankPrivi == -1)
return "privi=" + this.namePrivi;
else
return "privi=" + this.namePrivi + ":" + this.rankPrivi;
}
/**
*重寫equals方法
*/
public Boolean equals(Privilege p) {
if(this.namePrivi.equals(p.namePrivi) && (this.rankPrivi == p.rankPrivi))
return true;
return false;
}
}
測試的時候,自己構造一個比較好的樣例也是很重要的。題目中給出的樣例漏了幾個關鍵的資訊,如果不補上相關的資訊,自己測試不出問題,但是一提交就說錯誤。
下面是我自己的樣例,不一定就合適,但是可以做參考吧:
樣例輸入:
3
crm:2
git:3
game
4
hr 2 crm:2 crm:1
it 3 crm:1 git:1 game
dev 2 git:3 game
qa 1 git:0
4
alice 2 hr it
bob 2 it qa
charlie 1 dev
sunpro 1 qa
10
alice game
alice crm:2
bob git
bob poweroff
charlie game
charlie crm
charlie git:0
malice game
sunpro git
alice crm
樣例輸出結果:
true
true
1
false
true
false
true
false
0
2
下面的程式碼都是有問題的。沒有經過優化的:就不刪了,留著做對比吧。
我用java語言編寫,經過多次優化測試,終於符合要求。(更新:實際上,指示有一次樣例比較簡單,才符合要求了。後來再試效果也不好!)
下面貼出的程式碼
import java.util.Scanner;
public class Main {
//private static Privi[] arrayPrivi;
//private static Role[] arrayRole;
//private static User[] arrayUser;
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
// input Privission list
int p = cin.nextInt();
Privi[] arrayPrivi = new Privi[p];
//List<Privi> priviList = new ArrayList<Privi>();
for (int i = 0; i < p; i++) {
arrayPrivi[i] = new Privi(cin.next());
}
// input role list
int r = cin.nextInt();
Role[] arrayRole = new Role[r];
for (int i = 0; i < r; i++) {
String name = cin.next();
int countrole = cin.nextInt();
Role ro = new Role(name, countrole);
for (int j = 0; j < countrole; j++) {
ro.addPrivi(j, new Privi(cin.next()));
}
arrayRole[i] = ro;
}
// input user list;
int u = cin.nextInt();
User[] arrayUser = new User[u];
for (int i = 0; i < u; i++) {
String name = cin.next();
int countrole = cin.nextInt();
User us = new User(name,countrole);
for (int j = 0; j < countrole; j++) {
us.addRole(j, roleFactory(arrayRole,cin.next()));
}
arrayUser[i] = us;
}
//
int q = cin.nextInt();
Query[] arrayQuery = new Query[q];
for (int i = 0; i < q; i++) {
arrayQuery[i] = new Query(cin.next(),cin.next());
}
cin.close();
//query
//long timeBefore = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (Query query : arrayQuery) {
sb.append(check(query,arrayUser) + "\n");
}
System.out.println(sb.toString());
//long timeAfter = System.currentTimeMillis();
//System.out.println("use time:" + (timeAfter - timeBefore));
}
/**
*
*/
private static Role roleFactory(Role[] arrayRole,String name) {
for(Role role : arrayRole) {
if(name.equals(role.getName())) {
return role;
}
}
return null;
}
/**
*/
private static String check(Query query,User[] arrayUser) {
int flag = -3;
String uname = query.qUserName;
Privi up = query.qPrivi;
for (User user : arrayUser) {
flag = -3;
if (uname.equals(user.getName())) {
Role[] userRoleArr = user.getRoleArray();
for (Role role : userRoleArr) {
Privi[] userRolePriviArr = role.getPriviArray();
for (Privi privi : userRolePriviArr) {
int temp = up.equals(privi);
flag = (temp > flag) ? temp : flag;
if(flag == -1) return "true";
}
}
break;
}
}
if (flag == -2 || flag == -3) {
return "false";
} else
return flag + "";
}
static class Query {
public String qUserName;
public Privi qPrivi;
Query(String username, String Priviname) {
this.qUserName = username;
this.qPrivi = new Privi(Priviname);
}
}
}
class Privi {
private String name;
private int level;
public Privi() {}
public Privi(String per) {
String[] p = per.split(":");
if (p.length == 1) {
Privi.this.name = p[0];
Privi.this.level = -1;
} else if (p.length == 2) {
Privi.this.name = p[0];
Privi.this.level = Integer.parseInt(p[1]);
}
}
public String getName() {
return this.name;
}
public void setName(String s) {
this.name = s;
}
public int getLevel() {
return this.level;
}
public void setLevel(int l) {
this.level = l;
}
public int equals(Privi p) {
if (this.name.equals(p.getName())) {
if(this.level == -1 && this.level < p.getLevel())
return p.getLevel();
else if(this.level == -1 && p.getLevel() == -1)
return -1;//bufendengji
else if(this.level != -1 && this.level <= p.getLevel() )
return -1;//fendengji
else
return -2; //
} else
return -2;
}
public String toString() {
return this.name +(this.level != -1 ? (":" + this.level) : "");
}
}
class Role {
private String name;
private int countPrivi;
private Privi[] arrPrivi;
//private List<Privi> priList;
public Role() {
this.name = "";
//this.priList = new ArrayList<Privi>();
}
public Role(String n,int count) {
this.name = n;
this.countPrivi = count;
this.arrPrivi = new Privi[count];
}
public String getName() {
return this.name;
}
public void setName(String s) {
this.name = s;
}
public int getPriviCount() {
return this.arrPrivi.length;
}
public Privi[] getPriviArray() {
return this.arrPrivi;
}
public void addPrivi(int n,Privi p) {
this.arrPrivi[n] = p;
}
public String toString() {
String s = this.name + "~" ;
for(Privi p : this.arrPrivi) {
s += p.toString() + "+";
}
return s;
}
}
class User {
private String name;
private int countRole;
private Role[] arrRole;
public User() {
this.name = "";
//this.roleList = new ArrayList<Role>();
}
public User(String name, int count) {
this.name = name;
this.countRole = count;
this.arrRole = new Role[count];
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Role[] getRoleArray() {
return this.arrRole;
}
public void addRole(int n, Role role) {
this.arrRole[n] = role;
}
public String toString() {
String s = name + "~";
for(Role role : arrRole) {
s += role.toString() + "+";
}
return s;
}
}
下面的是最早的版本,執行結果正確,但是執行超時。可以與上面進行對比。主要優化點有:
(1)將List改為Array;
(2)將全域性變數改為區域性變數;
(3)輸出採用StringBuilder;
(4)check()方法中,進一步精確了終止迴圈的時間;這應該是最顯著的改善點。
import java.util.List;
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
private static List<Privi> priviList = new ArrayList<Privi>();
private static List<Role> roleList = new ArrayList<Role>();
private static List<User> userList = new ArrayList<User>();
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
// input Privilege list
int p = cin.nextInt();
for (int i = 0; i < p; i++) {
priviList.add(new Privi(cin.next()));
}
// input role list
int r = cin.nextInt();
for (int i = 0; i < r; i++) {
//
Role ro = new Role(cin.next());
int pn = cin.nextInt();
for (int j = 0; j < pn; j++) {
ro.addPrivi(new Privi(cin.next()));
}
roleList.add(ro);
}
// input user list;
int u = cin.nextInt();
for (int i = 0; i < u; i++) {
User us = new User(cin.next());
int rn = cin.nextInt();
for (int j = 0; j < rn; j++) {
us.addRole(roleFactory(cin.next()));
}
userList.add(us);
}
//
int q = cin.nextInt();
List<Query> queryList = new ArrayList<Query>();
for (int i = 0; i < q; i++) {
Query qu = new Query(cin.next(),cin.next());
queryList.add(qu);
}
//query
for (Query query : queryList) {
System.out.println(check(query));
}
cin.close();
}
/**
*
*/
private static Role roleFactory(String name) {
for(Role role : roleList) {
if(name.equals(role.getName())) {
return role;
}
}
return null;
}
/**
*/
private static String check(Query query) {
int flag = -3;
for (User user : userList) {
flag = -3;
if (query.qUserName.equals(user.getName())) {
List<Role> userRoleList = user.getRoleList();
for (Role role : userRoleList) {
List<Privi> userRolePriviList = role.getPriviList();
for (Privi privi : userRolePriviList) {
int temp = query.qPrivi.equals(privi);
flag = (temp > flag) ? temp : flag;
if(flag == -1) break;
}
if(flag == -1) break;
}
}
if (flag != -3) {
break;
}
}
if (flag == -2 || flag == -3) {
return "false";
} else if(flag == -1) {
return "true";
} else
return flag + "";
}
static class Query {
public String qUserName;
public Privi qPrivi;
Query() {
qUserName = "";
qPrivi = new Privi();
}
Query(String username) {
this.qUserName = username;
this.qPrivi = new Privi();
}
Query(String username, String Priviname) {
this.qUserName = username;
this.qPrivi = new Privi(Priviname);
}
}
static class Privi {
private String name;
private int level;
public Privi() {}
public Privi(String per) {
String[] p = per.split(":");
if (p.length == 1) {
Privi.this.name = p[0];
Privi.this.level = -1;
} else if (p.length == 2) {
Privi.this.name = p[0];
Privi.this.level = Integer.parseInt(p[1]);
}
}
public String getName() {
return this.name;
}
public void setName(String s) {
this.name = s;
}
public int getLevel() {
return this.level;
}
public void setLevel(int l) {
this.level = l;
}
public int equals(Privi p) {
if (this.name.equals(p.getName())) {
if(this.level == -1 && this.level < p.getLevel())
return p.getLevel();
else if(this.level == -1 && p.getLevel() == -1)
return -1;//bufendengji
else if(this.level != -1 && this.level <= p.getLevel() )
return -1;//fendengji
else
return -2; //
} else
return -2;
}
public String toString() {
return this.name +(this.level != -1 ? (":" + this.level) : "");
}
}
static class Role {
private String name;
private List<Privi> priList;
public Role() {
this.name = "";
this.priList = new ArrayList<Privi>();
}
public Role(String n) {
this.name = n;
this.priList = new ArrayList<Privi>();
}
public String getName() {
return this.name;
}
public void setName(String s) {
this.name = s;
}
public int getPriviCount() {
return this.priList.size();
}
public List<Privi> getPriviList() {
return this.priList;
}
public void addPrivi(Privi p) {
this.priList.add(p);
}
public String toString() {
String s = this.name + "~" ;
for(Privi p : this.priList) {
s += p.toString() + "+";
}
return s;
}
}
static class User {
private String name;
private List<Role> roleList;
public User() {
this.name = "";
this.roleList = new ArrayList<Role>();
}
public User(String name) {
this.name = name;
this.roleList = new ArrayList<Role>();
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public List<Role> getRoleList() {
return this.roleList;
}
public void addRole(Role role) {
this.roleList.add(role);
}
public String toString() {
String s = name + "~";
for(Role role : roleList) {
s += role.toString() + "+";
}
return s;
}
}
}