题目如下:
试题编号: |
202206-3 |
试题名称: | 角色授权 |
时间限制: | 5.0s |
内存限制: | 512.0MB |
问题描述: | 题目背景为了响应国家发展新基建的倡议,西西艾弗岛上兴建了西西艾弗数据中心,并以此为基础运营了西西艾弗云。作为数据中心的运营和维护方, 这种安全模型将验证流程分为两个步骤。第一步是验证用户的身份(鉴别),第二步是验证用户的权限(授权)。在第一步, 为了能够灵活地表达用户和授权之间的关系,西西艾弗云公司设计了一种简洁而灵活的授权模型:基于角色的授权模型。它的思路是:首先设定若干角色, 小 C 将实现授权模型的工作交给了你,希望你能够把它们实现出来。 问题描述用户表示授权模型中的一个已识别的主体,该识别过程由此前的鉴别过程完成。一个用户具有下列要素:
一个待授权的行为,包括下列要素:
需要注意的是,一个待授权的行为的主体信息,即用户名称和所属用户组,是由前一步骤的鉴别过程完成的。因此,每次授权过程中, 角色是这种授权模型的基本单位,它指明了一个用户可以执行的操作,角色的清单中描述了角色所允许的操作。一个角色包含下列要素:
判断一个角色能否对某个资源执行某个操作的过程是:
例如,假设有某个角色 角色关联指明了一个用户和一个或多个角色之间的关系。一个角色关联包含下列要素:
判断一个用户能否执行某个操作的过程是:
由此可见,一个角色关联可以将一个角色与多个用户或用户组关联起来。例如,如果有一个角色关联,其关联的角色名称为
但是,属于用户组 从上述判断规则可以知道,一个用户可能与多个角色相关联,在这种情况下,该用户允许进行的操作是这些角色被允许进行的操作集合的并集。 输入格式从标准输入读入数据。 输入的第一行包含三个正整数 n、m、q,分别表示角色数量、角色关联数量和待检查的操作数量。 输入接下来的 n 行中,每行表示一个角色,包括空格分隔的若干元素,依次为:
输入接下来的 m 行中,每行表示一个角色关联,包括空格分隔的若干元素,依次为:
输入接下来的 q 行中,每行表示一个待授权的行为,包括空格分隔的若干元素,依次为:
输出格式输出到标准输出。 输出 q 行,每行表示一个操作是否可以被执行, 样例输入 Data 样例输出 Data 样例解释在本例中,定义了一个名为 子任务对于 20% 的数据,有 n=m=1,且给出的角色类似于题目正文中用于举例的 对于 40% 的数据,有 1≤n,m≤50,且 nv=no=ns=1、ng≤40、nn=0。 对于 70% 的数据,有 1≤n,m≤50,且 nv,no,ns,ng≤40、nn≤400。 对于 100% 的数据,有:
|
原题链接:角色授权
先说成果,第一次提交运行超时70分,第二次提交满分通过(虽然显示运行时间超过规定的5s,至于原因我也不得清楚)
试题名称 | 提交时间 | 代码长度 | 编程语言 | 评测结果 | 得分 | 时间使用 | 空间使用 | |||
---|---|---|---|---|---|---|---|---|---|---|
角色授权 | 07-20 22:17 | 1.421KB | PYTHON | 正确 | 100 | 11.82s | 79.86MB | |||
角色授权 | 07-20 19:44 | 2.257KB | PYTHON | 运行超时 | 70 | 运行超时 | 54.07MB |
下面分析解题思路:其实解题思路题目已经给出来了,如下:
判断一个用户能否执行某个操作的过程是:
按照这个思路,我的解题做法是创建两个类分别对应角色和角色关联,每个角色实例有四个属性:角色名、操作、资源种类、资源名称,后个属性都用列表表示。每个角色关联有两个属性:关联角色名、关联用户、关联用户组,同样后两个属性用列表表示。
将所有输入的角色实例和角色关联实例创建实例对象,然后对每个输入的待授权的操作,遍历所有角色关联实例,先、后判断用户、用户组是否存在于当前角色关联实例的关联用户属性、关联用户组中,只要满足一个存在则继续判断当前角色关联实例的关联角色属性对应的角色实例能否授权操作。如果能,记录当前操作为授权(也就是1),然后接受下一个待授权操作,否则,遍历下一个角色关联实例,重复步骤直到所有角色关联实例都遍历完,若此时当前操作依然未被授权,则记录当前操作为不授权(也就是0),然后接受下一个待授权操作。
下面为代码实现(70分)
def pd(jsm,czm,zylm,zym):
jsm = jname[jsm]
if jsm.pcz(czm) == 0:
return 0
if jsm.pzyl(zylm) == 0:
return 0
if jsm.pzy(zym) == 0:
return 0
return 1
class js:
def __init__(self,name):
self.name = name
self.czj0 = 0
self.zylj0 = 0
def cz(self,czj):
self.czj = czj
if '*' in czj:
self.czj0 = 1
def zyl(self,zylj):
self.zylj = zylj
if '*' in zylj:
self.zylj0 = 1
def zy(self,zyj):
self.zyj = zyj
def pcz(self,cz):
if self.czj0 == 1:
return 1
if cz in self.czj:
return 1
else:return 0
def pzyl(self,zyl):
if self.zylj0 == 1:
return 1
if zyl in self.zylj:
return 1
else:return 0
def pzy(self,zyj):
if self.zyj == []:
return 1
if zyj in self.zyj:
return 1
else:return 0
class jsl:
def __init__(self,name):
self.name = name
self.u = []
self.g = []
def uyh(self,udx):
self.u.append(udx)
def gyh(self, gdx):
self.g.append(gdx)
def udx(self,yh):
if yh in self.u:
return 1
else:return 0
def gdx(self,yhz):
for yh in yhz:
if yh in self.g:
return 1
return 0
n,m,q = map(int,input().split())
jsj = []
jslj = []
jname = {}
for i in range(n):
L = list(input().split())
jsj.append(js(L[0]))
jname[L[0]] = jsj[i]
nv = int(L[1])
no = int(L[2 + nv])
nn = int(L[3 + nv + no])
jsj[i].cz(L[2:2+nv])
jsj[i].zyl(L[3+nv:3+nv+no])
jsj[i].zy(L[4+nv+no:])
for i in range(m):
L = list(input().split())
jslj.append(jsl(L[0]))
ns = int(L[1])
for j in range(ns):
if L[2*(j+1)] == 'u':
jslj[i].uyh(L[2*(j+1)+1])
else:jslj[i].gyh(L[2*(j+1)+1])
sc = [0]*q
for i in range(q):
L = list(input().split())
yh = L[0]
ng = int(L[1])
yhz = L[2:ng+2]
dcz = L[-3]
dzyl = L[-2]
dzy = L[-1]
for j in jslj:
if j.udx(yh) == 1 or j.gdx(yhz) == 1:
if pd(j.name,dcz,dzyl,dzy) == 1:
sc[i] = 1
break
for i in sc:
print(i)
提交后显示运行超时,分析原因:在最坏情况下,对每个待授权操作,都是要遍历所有角色关联实例,继而遍历角色关联实例下所有用户和用户组。当数据量巨大时,超时是必然的。
解决方法:可以将角色关联实例反过来做成用户关联实例和用户组关联实例,这样可以直接找到关联当前用户或用户组的角色。
另外优化:每个角色都要创建实例对象,这同样会耗费大量时间,单从解题目的出发,其实可以不创建实例对象,直接对输入的信息操作。
代码实现如下(满分):
def pc(x,y):
if '*' in x or y in x:
return 1
return 0
def pzy(x,y):
if x == [] or y in x:
return 1
return 0
def pd(jsm,czm,zylm,zym):
if jsm in jname:
p = jname[jsm]
else:return 0
nv = int(p[1])
no = int(p[2 + nv])
if pc(p[2:2+nv],czm) == 0:
return 0
if pc(p[3+nv:3+nv+no],zylm) == 0:
return 0
if pzy(p[4+nv+no:],zym) == 0:
return 0
return 1
n,m,q = map(int,input().split())
jsg = {}
jsu = {}
jname = {}
for i in range(n):
L = list(input().split())
jname[L[0]] = L
for i in range(m):
L = list(input().split())
ns = int(L[1])
for j in range(ns):
if L[2*(j+1)] == 'u':
if L[2*(j+1)+1] in jsu:
jsu[L[2*(j+1)+1]].add(L[0])
else:
jsu[L[2*(j+1)+1]] = {L[0]}
else:
if L[2*(j+1)+1] in jsg:
jsg[L[2*(j+1)+1]].add(L[0])
else:
jsg[L[2*(j+1)+1]] = {L[0]}
sc = [0]*q
for j in range(q):
L = list(input().split())
yh = L[0]
ng = int(L[1])
yhz = L[2:ng+2]
dcz = L[-3]
dzyl = L[-2]
dzy = L[-1]
if yh in jsu:
jsj = jsu[yh]
else:
jsj = set()
for i in yhz:
if i in jsg:
jsj = jsj.union(jsg[i])
if len(jsj) == 0:
continue
for i in jsj:
if pd(i, dcz, dzyl, dzy) == 1:
sc[j] = 1
break
for i in sc:
print(i)