21608: 你和你比较熟悉的同学
bfs/dfs and similar, http://cs101.openjudge.cn/practice/21608
2020年秋季学期,Henry老师讲授北京大学《计算概论B》课程,其中12班127人,13班37人。临近期末,12月18日做了一个简单的问卷调查。以这种方式做为一次点名,同时也希望了解学生们的一些情况。
问卷内容是:写出自己和脑海中的班里(包括12班、和13班)的另外4名同学的名字。每位同学的名字用一个不重复的正整数表示。如果认识的同学少于4个,也可以少填写。每位同学最多提交1次问卷调查。
根据收集到的结果,形成了一张班级社会网络图 G = (V, E),如下所示。V是顶点的集合,E是边的集合 。在这个有向图G中,每位同学是一个顶点,边是认识关系。注意认识关系是单向的,即甲认识乙,不代表乙认识甲。
Henry老师想知道在有向图G中,找最大有向子树,所包含的顶点的个数。
【说明:对于一个点,计算从这个点(包括自己)开始沿着有向边能到达的点的数量。】

输入格式
输入第一行为一个数字
第
输出格式
输出一个整数。表示找到的最大有向子树,所包含的顶点的个数。
样例输入1
sample1 in:
5
53 : -1
118 : 119 136 137
92 : 107 93 102 91
102 : -1
130 : 66 132 135 103样例输出1
5
说明:表示从一个点出发,沿着有向边走,最多5个点连通。
130->66,130->132,130->135,130->103. 五个点包括:130、66、132、135和103.样例输入2
13
53 : -1
118 : 119 136 137
92 : 107 93 102 91
102 : -1
130 : 66 132 135 103
42 : 39 40 41
39 : 42 40 41 127
43 : 94
134 : 135 132 131 128
136 : 119 118 176 139
17 : 16 39 42
96 : 81 102 162 101
141 : 142样例输出2
7
说明:17->16,17->39,17->42; 39->40,39->41,39->127.
七个点包括:17、16、39、42、40、41和127.来源:cs101 2020
解题思路:需要求的是能够接触到的所有节点的最大值,而不是一条线走到底的最大值。bfs, dfs都可以过。dfs可以练习递归写法,非递归写法。如果有两人互相认识,可能会导致搜索在两人间互为循环,所以要用记录已经搜索到的元素。
# OJ 21608
# https://www.codespeedy.com/breadth-first-search-algorithm-in-python/
def bfs(graph, initial):
visited = []
queue = [initial]
while queue:
node = queue.pop(0)
if node not in visited:
visited.append(node)
if node not in graph:
continue
for nei in graph[node]: # neighbour
queue.append(nei)
return visited
# https://stackoverflow.com/questions/43430309/depth-first-search-dfs-code-in-python
# https://www.codespeedy.com/depth-first-search-algorithm-in-python/
def dfs(graph, node, visited):
if node not in visited:
visited.append(node)
if node not in graph:
return visited
for nei in graph[node]: # neighbour
dfs(graph, nei, visited)
return visited
def dfs_Non_recursion(graph, initial):
visited = [initial]
stack = [initial]
while stack:
node = stack[-1]
if node not in visited:
visited.append(node)
if node not in graph:
stack.pop()
continue
remove_from_stack = True
for nei in graph[node]: # neighbour
if nei not in visited:
stack.append(nei)
remove_from_stack = False
break
if remove_from_stack:
stack.pop()
return visited
## create graph
graph = {}
ids = set()
for _ in range(int(input())):
ln = input().split(':')
u = int(ln[0].rstrip())
ids.add(u)
if u not in graph:
neighbours = [int(_) for _ in ln[1].split()]
graph[u] = neighbours
## bfs travel
maxp = 0
for i in ids:
bfs_path = bfs(graph, i)
if -1 in bfs_path:
bfs_path.remove(-1)
maxp = max(maxp, len(bfs_path))
#print(len(bfs_path), bfs_path)
#print(maxp)
## dfs_Non_recursion travel
maxp = 0
for i in ids:
dfs_path = dfs_Non_recursion(graph, i)
if -1 in dfs_path:
dfs_path.remove(-1)
maxp = max(maxp, len(dfs_path))
#print(len(bfs_path), bfs_path)
print(maxp)
## dfs travel
maxp = 0
for i in ids:
dfs_path = dfs(graph, i, [])
if -1 in dfs_path:
dfs_path.remove(-1)
maxp = max(maxp, len(dfs_path))
#print(len(dfs_path), dfs_path)
#print(maxp)2021fall-cs101,黄章毅。
这个题目的bfs 采用集合来储存数据,可以通过集合的减法直接减掉visited 里的元素,并且加入元素也比较方便,这得益于在做Kefa and Park 一题时,在codeforces 上看其他同学,AC 的代码时,感觉这样处理更加方便直观,于是就在这个题重新写尝试了一下。
# http://cs101.openjudge.cn/practice/21608
d,ans={-1:set()},[]
for _ in range(int(input())):
l=input().split()
d[int(l[0])]=set([int(i) for i in l[2:]])
def bfs(i):
queue,visited=[i],{i}
while queue:
node=queue.pop(0)
visited.add(node)
queue=queue+list(d.get(node,set())-visited)
if len(d.get(node,set())-visited)==0:
ans.append(len(visited-{-1}))
for i in d.keys():
bfs(i)
print(max(ans))