哔哩哔哩2018.9.21笔试 小A最多会新认识多少人
题目描述
小A参加一个n人的活动,每个人都有一个编号(0<=i<=n-1),其中有m对相互认识,在活动中两个人可以通过互相都认识都认识的一个人介绍认识。现在问活动结束后,小A最多会新认识多少人?
输入:
第一行是聚会人数n
第二行是小A的编号a
接下来m行为互相认识的对,以’,'分割
输出:
小A最多会新认识多少人的人数。
样例输入:
7
5
6
1,0
3,1
4,1
5,3
6,1
6,5
样例输出:
3
提示:
小A新认识的人为【0,1,4】
深度遍历
1.分析这句话“个人可以通过互相都认识都认识的一个人介绍认识”,所以最终,有间接认识关系的人都会互相认识。
2.该问题是一个无向图的深度遍历。深度递归到的节点都是小A的朋友(包括初始朋友和新朋友)。
3.在深度遍历的过程中,把小A新认识的人加入一个集合中,最后输出这个集合的长度。
4.注意不要把小A和小A初始已经认识的朋友加入集合中
5.考虑到整个图可能是不连通的,所以必须从a开始进行深度遍历
n = eval(input())
a = eval(input())
m = eval(input())
from collections import defaultdict
d = defaultdict(list)
for i in range(m):
start,end = map(int,input().split(','))
d[start].append(end)
d[end].append(start)
visited = [False]*n
visited[a] = True
friend = set()
def recur(i):
if (i != a) and (i not in d[a]):
#注意不要把小A和小A初始已经认识的朋友加入集合中
friend.add(i)
if (d[i] == []):
return
for re in d[i]:
if visited[re] == False:
visited[re] = True
recur(re)
#visited[re] = False
#注意这里在递归回来时不用恢复visited,因为在这里只需要考虑深度遍历到的有哪些节点
#而是不是新朋友,交给递归函数里的第一个if判断就可以了
#加了这句反而会使有些节点被重复得递归到
recur(a)
print(len(friend))
该代码中如果没有注释掉visited[re] = False
,有些递归分支会作一些无用功。比如递归到6后,会递归到1;而递归到3后,又会递归到1(之后还有重复的递归)。
思考与总结
虽然你看我现在思路这么清晰,当时笔试的时候却理解错了题意,我以为输出集合是【3,6,1】,因为以为此题是深度遍历但最大深度为2,然后代码通过率一直只有67%(多亏测试用例“设计得好”,不然我感觉连67%都没有,手动苦瓜脸)。做题还是应该把题意理解清楚了再做。
看来我是没有机会用爱发电了,债见B站。