Skip to content

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中,找最大有向子树,所包含的顶点的个数。

【说明:对于一个点,计算从这个点(包括自己)开始沿着有向边能到达的点的数量。】

img

输入格式

输入第一行为一个数字 n1<n200 ),表示调查问卷反馈人数。

2n+1 行是同学之间的认识关系。 每一行中,分号之前是提交问卷同学名字,之后是认识的同学名字。 -1表示没有熟悉的同学。 分号及整数,由空格分隔。

输出格式

输出一个整数。表示找到的最大有向子树,所包含的顶点的个数。

样例输入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可以练习递归写法,非递归写法。如果有两人互相认识,可能会导致搜索在两人间互为循环,所以要用记录已经搜索到的元素。

Python
# 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 的代码时,感觉这样处理更加方便直观,于是就在这个题重新写尝试了一下。

python
# 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))