哔哩哔哩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站。

posted @ 2018-09-23 20:06  allMayMight  阅读(118)  评论(0编辑  收藏  举报