阿里巴巴笔试4.20场
1.英雄和怪都有能力值,英雄只能打能力值小于自己能力值的怪,每打完一只怪获得一个金币,任意时刻可以用一个金币换取 1 点能力值,但金币数不能为负(初始为0)。英雄可以以随意顺序打怪,怪物可以不用打完,求可获取金币数的最大值。
>> 输入
1 3
2 2 1
说明:第一行第一个数表示英雄的初始能力值,第二个数表示怪物总数;第二行表示每个怪物的能力值
>> 输出
2
说明:英雄先打了能力值为 1 的怪物,把获得的 1 金币换成 1 点能力值,则现在有 2 点能力值,把剩下的怪物打完,总共获得 2 金币
import sys
def solve(a, n, blist):
blist = sorted(blist)
curr_a = a #能力值
curr_g = 0 #当前的金币值
max_g = 0 #可获取的金币最大值
for tb in blist:
if curr_a >= tb:
curr_g += 1
max_g = max(max_g,cur_g)
elif cur_g<(tb - curr_a): #当前金币全部用来购买能力都打不过怪兽了,则退出循环
break
else:
curr_g -= (tb - curr_a) #花费金币购买能力
curr_a = tb #更新能力值
curr_g += 1 #更新完能力值后继续打怪
max_g = max(max_g,cur_g)
return max_g
lines = [t.strip().split() for t in sys.stdin.readlines() if t.strip()]
a, n = int(lines[0][0]), int(lines[0][1])
blist = [int(t) for t in lines[1]]
print (solve(a, n, blist))
2.有 n 个城市,每个城市有一个等级值,这 n 个城市之间有 n-1 条边,每条边的时间权重都为 1,构成树结构。问:从任意城市到达另一个等级相同的城市,路径中不能有重复边,最小的时间是多少?(如果没有符合要求的路径,就返回 -1)
>> 输入
3
1 2 1
1 2
2 3
说明:第一行的数代表城市数 n,第二行代表每个城市的等级值,接下来的 n-1 行代表每条边的连接情况
>> 输出
2
说明:从城市 1 到城市 3,等级都为 1,经过时间是 2
import sys
def solve(n, alist, edges): #城市个数;城市等级;城市的边
adic = {} #{城市i:该城市的等级j}
reverse_adic = {} #{等级j:该等级对应的城市个数m}
for i, ta in enumerate(alist):
adic[i + 1] = ta
reverse_adic.setdefault(ta, 0)
reverse_adic[ta] += 1
adj_dic = {} #{城市i:和城市i相连的城市列表}
for f, t in edges:
adj_dic.setdefault(f, [])
adj_dic.setdefault(t, [])
#无向边
adj_dic[t].append(f)
adj_dic[f].append(t)
ans_min = None
for tp in adj_dic:#循环遍历城市的每一个节点tp
pa = adic[tp] #城市tp的等级(初始节点的等级!)
if reverse_adic[pa] <= 1: #如果城市tp的等级对应的城市个数小于2,则退出本次循环
continue
used_edge = set() #题目要求路径中不能有重复边
queue = [(tp, 0)] #(初始节点tp,当前花费的时间)
flag = False
mindist = None
for r, tdist in queue:
for nxt in adj_dic[r]: #adj_dic[r]为节点r的所有相连节点列表,r -> nxt
#如果路径没有走过
if (r, nxt) not in used_edge and (nxt, r) not in used_edge:
#如果相连节点对应的等级等于初始节点tp的等级,则结束了从tp节点开始的循环
if adic[nxt] == pa:
flag = True
mindist = tdist + 1
break
#没有结束,就继续找
queue.append((nxt, tdist + 1))#queue中加元素会在for r, tdist in queue会继续处理!
#使用过的边需要记录,下次不可以继续使用了
used_edge.add((r, nxt))
#如果已经找到了就不需要继续遍历queue中元素了
if flag:#情况:某个节点有两个相连节点,就对用两条往下走的边,其中一条边找到了,就不需要继
break #续在另一条找了
if ans_min == None or mindist < ans_min:
ans_min = mindist 更新最小时间
return -1 if ans_min == None else ans_min
lines = [t.strip().split() for t in sys.stdin.readlines() if t.strip()]
n = int(lines[0][0])
alist = [int(t) for t in lines[1]]
edges = [(int(f), int(t)) for f, t in lines[2:]]
print (solve(n, alist, edges))