阿里巴巴笔试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))

 

posted @ 2020-04-21 10:41  USTC丶ZCC  阅读(336)  评论(0编辑  收藏  举报